Files
cloud-host/backend/k8s/mail/maddy.yaml
T
keyhan 5ed2ef0958
Build and Deploy Platform / build-push-deploy (push) Has been cancelled
Add GitOps stack for abrban.com with Gitea Actions CI/CD.
Harbor in-cluster builds via Kaniko, ArgoCD auto-sync, and production Helm values for abrban.com domains.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 01:27:20 +03:30

249 lines
6.5 KiB
YAML

# Maddy mail server — lightweight full mail server (SMTP + IMAP + DKIM)
# Namespace: mail | Host: mail.abrban.com | Primary domain: abrban.com
#
# Exposed on node IP 78.157.39.52 via k3s servicelb (klipper).
# TLS uses the *.abrban.com wildcard cert (secret abrban-wildcard-tls, copied into ns mail).
#
# NOTE (Iran/IP reputation): inbound mail (receiving) works; outbound delivery to
# Gmail/Outlook may be blocked or land in spam, and outbound port 25 may be filtered
# by the ISP. Use a smarthost relay if real external delivery is required.
---
apiVersion: v1
kind: ConfigMap
metadata:
name: maddy-config
namespace: mail
data:
maddy.conf: |
## Maddy Mail Server - configuration (mail.abrban.com)
$(hostname) = mail.abrban.com
$(primary_domain) = abrban.com
$(local_domains) = $(primary_domain)
tls file /etc/maddy/tls/tls.crt /etc/maddy/tls/tls.key
# ---- Local storage & authentication ----
storage.imapsql local_mailboxes {
driver sqlite3
dsn imapsql.db
}
auth.pass_table local_authdb {
table sql_table {
driver sqlite3
dsn credentials.db
table_name passwords
}
}
# ---- Routing ----
hostname $(hostname)
table.chain local_rewrites {
optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3"
optional_step static {
entry postmaster postmaster@$(primary_domain)
}
optional_step file /data/aliases
}
msgpipeline local_routing {
destination postmaster $(local_domains) {
modify {
replace_rcpt &local_rewrites
}
deliver_to &local_mailboxes
}
default_destination {
reject 550 5.1.1 "User doesn't exist"
}
}
# ---- Inbound SMTP (port 25) ----
smtp tcp://0.0.0.0:25 {
limits {
all rate 20 1s
all concurrency 10
}
dmarc yes
check {
require_mx_record
dkim
spf
}
source $(local_domains) {
reject 501 5.1.8 "Use Submission for outgoing SMTP"
}
default_source {
destination postmaster $(local_domains) {
deliver_to &local_routing
}
default_destination {
reject 550 5.1.1 "User doesn't exist"
}
}
}
# ---- Submission (ports 465 implicit-TLS, 587 STARTTLS) ----
submission tls://0.0.0.0:465 tcp://0.0.0.0:587 {
limits {
all rate 50 1s
}
auth &local_authdb
source $(local_domains) {
check {
authorize_sender {
prepare_email &local_rewrites
user_to_email identity
}
}
destination postmaster $(local_domains) {
deliver_to &local_routing
}
default_destination {
modify {
dkim $(primary_domain) $(hostname) default
}
deliver_to &remote_queue
}
}
default_source {
reject 501 5.1.8 "Non-local sender domain"
}
}
# ---- Outbound delivery queue ----
target.remote outbound_delivery {
limits {
destination rate 20 1s
destination concurrency 10
}
mx_auth {
dane
mtasts {
cache fs
fs_dir mtasts_cache/
}
local_policy {
min_tls_level encrypted
min_mx_level none
}
}
}
target.queue remote_queue {
target &outbound_delivery
autogenerated_msg_domain $(primary_domain)
bounce {
destination postmaster $(local_domains) {
deliver_to &local_routing
}
default_destination {
reject 550 5.0.0 "Refusing to send DSNs to non-local addresses"
}
}
}
# ---- IMAP (993 implicit-TLS, 143 STARTTLS) ----
imap tls://0.0.0.0:993 tcp://0.0.0.0:143 {
auth &local_authdb
storage &local_mailboxes
}
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: maddy-data
namespace: mail
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: local-path
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: maddy
namespace: mail
labels:
app: maddy
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: maddy
template:
metadata:
labels:
app: maddy
spec:
containers:
- name: maddy
image: foxcpp/maddy:0.7
imagePullPolicy: IfNotPresent
env:
- name: MADDY_HOSTNAME
value: mail.abrban.com
- name: MADDY_DOMAIN
value: abrban.com
ports:
- { name: smtp, containerPort: 25 }
- { name: submission, containerPort: 587 }
- { name: smtps, containerPort: 465 }
- { name: imap, containerPort: 143 }
- { name: imaps, containerPort: 993 }
volumeMounts:
- name: data
mountPath: /data
- name: config
mountPath: /data/maddy.conf
subPath: maddy.conf
- name: tls
mountPath: /etc/maddy/tls
readOnly: true
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: "1"
memory: 256Mi
livenessProbe:
tcpSocket: { port: 25 }
initialDelaySeconds: 15
periodSeconds: 30
volumes:
- name: data
persistentVolumeClaim:
claimName: maddy-data
- name: config
configMap:
name: maddy-config
- name: tls
secret:
secretName: abrban-wildcard-tls
---
apiVersion: v1
kind: Service
metadata:
name: maddy
namespace: mail
labels:
app: maddy
spec:
type: LoadBalancer
externalTrafficPolicy: Local # preserve client source IP (needed for SPF/spam checks)
selector:
app: maddy
ports:
- { name: smtp, port: 25, targetPort: 25 }
- { name: submission, port: 587, targetPort: 587 }
- { name: smtps, port: 465, targetPort: 465 }
- { name: imap, port: 143, targetPort: 143 }
- { name: imaps, port: 993, targetPort: 993 }