[KUBE](../README.md)  /  Mail server # Mail server ## Template of zone ```zone $TTL 300 @ IN SOA ns1.mydns.example. dnsadmin.mydomain.com. ( 2025091001 ; serial 3600 ; refresh 900 ; retry 1209600 ; expire 300 ; minimum ) IN NS ns1.mydns.example. IN NS ns2.mydns.example. ; ===== A/AAAA ===== mta IN A {{PUBLIC_IPV4}} ; mta IN AAAA {{PUBLIC_IPV6}} ; if available ; if desired, client sites can resolve to the same IP {{US1}} IN A {{PUBLIC_IPV4}} {{US2}} IN A {{PUBLIC_IPV4}} {{US3}} IN A {{PUBLIC_IPV4}} ; ===== MX ===== ; @ IN MX 10 mta.{{ROOT_DOMAIN}}. ; the root domain also accepts mail, if needed {{US1}} IN MX 10 mta.{{ROOT_DOMAIN}}. {{US2}} IN MX 10 mta.{{ROOT_DOMAIN}}. {{US3}} IN MX 10 mta.{{ROOT_DOMAIN}}. ; ===== SPF ===== ; @ IN TXT "v=spf1 mx ~all" ; if available mta IN TXT "v=spf1 a -all" {{US1}} IN TXT "v=spf1 mx ~all" {{US2}} IN TXT "v=spf1 mx ~all" {{US3}} IN TXT "v=spf1 mx ~all" ; ===== DKIM ===== ; For each customer domain, publish its own public key. ; The selector can be shared (e.g., selector1); keys are different. selector1._domainkey.{{US1}} IN TXT "v=DKIM1; k=rsa; p={{PUBKEY_US1}}" selector1._domainkey.{{US2}} IN TXT "v=DKIM1; k=rsa; p={{PUBKEY_US2}}" selector1._domainkey.{{US3}} IN TXT "v=DKIM1; k=rsa; p={{PUBKEY_US3}}" ; ===== DMARC ===== ; Initially p=none to collect reports without impacting delivery. _dmarc.{{US1}} IN TXT "v=DMARC1; p=none; adkim=r; aspf=r; rua=mailto:{{DMARC_AGG}}; ruf=mailto:{{DMARC_FOR}}" _dmarc.{{US2}} IN TXT "v=DMARC1; p=none; adkim=r; aspf=r; rua=mailto:{{DMARC_AGG}}; ruf=mailto:{{DMARC_FOR}}" _dmarc.{{US3}} IN TXT "v=DMARC1; p=none; adkim=r; aspf=r; rua=mailto:{{DMARC_AGG}}; ruf=mailto:{{DMARC_FOR}}" ; It is recommended to set DMARC on the root domain to cover ALL subdomains with a single policy. ; _dmarc IN TXT "v=DMARC1; p=quarantine; sp=quarantine; adkim=r; aspf=r; rua=mailto:{{DMARC_AGG}}; ruf=mailto:{{DMARC_FOR}}" ; (if test mode first — replace p=none, sp=none) ; ===== Additionally (optional but useful) ===== ; MTA-STS (if to implement) ;_mta-sts IN TXT "v=STSv1; id=2025-09-10" ;_smtp._tls IN TXT "v=TLSRPTv1; rua=mailto:tlsrpt@{{ROOT_DOMAIN}}" ;autoconfig IN CNAME autoconfig.mailhost.example. ; for client autoconfiguration ;autodiscover IN CNAME autodiscover.mailhost.example. ``` ```zone ; ===== PTR ===== {{PUBLIC_IPV4}} → mta.{{ROOT_DOMAIN}} ``` Check: Postfix HELO/EHLO = mta.`{{ROOT_DOMAIN}}` ## Example `{{ROOT_DOMAIN}}` → krumax.cz \ `{{PUBLIC_IPV4}}` → 31.31.73.67 \ `{{US1}}`/`{{US2}}`/`{{US3}}` → us1 / us2 / us3 \ `{{PUBKEY_US1}}`/`{{PUBKEY_US2}}`/`{{PUBKEY_US3}}` → DKIM public keys (only the content after `p=`, in a single line) \ `{{DMARC_AGG}}`/`{{DMARC_FOR}}` → Addresses for DMARC reports (for example, dmarc@krumax.cz) ```zone $TTL 300 ; ===== A ===== mta IN A 31.31.73.67 us1 IN A 31.31.73.67 us2 IN A 31.31.73.67 us3 IN A 31.31.73.67 ; ===== MX ===== us1 IN MX 10 mta.krumax.cz. us2 IN MX 10 mta.krumax.cz. us3 IN MX 10 mta.krumax.cz. ; ===== SPF ===== mta IN TXT "v=spf1 a -all" us1 IN TXT "v=spf1 mx ~all" us2 IN TXT "v=spf1 mx ~all" us3 IN TXT "v=spf1 mx ~all" ; ===== DKIM ===== selector1._domainkey.us1 IN TXT "v=DKIM1; k=rsa; p=MIIBI...(us1)" selector1._domainkey.us2 IN TXT "v=DKIM1; k=rsa; p=MIIBI...(us2)" selector1._domainkey.us3 IN TXT "v=DKIM1; k=rsa; p=MIIBI...(us3)" ; ===== DMARC ===== _dmarc.us1 IN TXT "v=DMARC1; p=none; adkim=r; aspf=r; rua=mailto:dmarc@krumax.cz; ruf=mailto:dmarc@krumax.cz" _dmarc.us2 IN TXT "v=DMARC1; p=none; adkim=r; aspf=r; rua=mailto:dmarc@krumax.cz; ruf=mailto:dmarc@krumax.cz" _dmarc.us3 IN TXT "v=DMARC1; p=none; adkim=r; aspf=r; rua=mailto:dmarc@krumax.cz; ruf=mailto:dmarc@krumax.cz" ``` ```zone ; ===== PTR ===== 31.31.73.67 → mta.krumax.cz ``` ## Example of adding a new domain in Postfix 1. Adding the domain and generating DKIM ```bash sudo kube.sh postfix add us2.krumax.cz ``` 2. Retrieving DKIM ```bash sudo kube.sh postfix dkim us2.krumax.cz ``` 3. Adding DNS records: ```zone us2 IN A 31.31.73.67 us2 IN MX 10 mta.krumax.cz. selector1._domainkey.us2 IN TXT "v=DKIM1; k=rsa; p=MIIBI...(from step 2)" _dmarc.us2 IN TXT "v=DMARC1; p=none; adkim=r; aspf=r; rua=mailto:dmarc@krumax.cz; ruf=mailto:dmarc@krumax.cz" ``` ## Send mail in PHP. Create file for test send mail `send-mail.php` ```php ", "Reply-To: $from", "Return-Path: $return", "Date: " . date('r'), "Message-ID: <" . time() . "." . bin2hex(random_bytes(6)) . "@" . $hostname . ">", "MIME-Version: 1.0", "Content-Type: text/plain; charset=UTF-8", "Content-Transfer-Encoding: quoted-printable", "List-Unsubscribe: , ", ]; $headersStr = implode("\r\n", $headers); $status = mail("$toName <$to>", $subject, $bodyQP, $headersStr, "-f$return"); echo $status ? "Success\n" : "Failed\n"; ``` ## Send mail in Wordpress. 1. Add Wordpress plugin `/wp-content/mu-plugins/smtp.php` ```php isSMTP(); $phpmailer->XMailer = 'krumaxMailer 1.0'; $phpmailer->Host = 'mta.krumax.cz'; $phpmailer->Port = 25; $phpmailer->SMTPAuth = false; $phpmailer->SMTPSecure = ''; $phpmailer->SMTPAutoTLS = false; $phpmailer->From = 'no-reply@us1.krumax.cz'; // $phpmailer->FromName = 'Support team US1'; // $phpmailer->Hostname = 'us1.krumax.cz'; // $phpmailer->Encoding = 'quoted-printable'; // $phpmailer->Sender = 'bounce@us1.krumax.cz'; // $phpmailer->Timeout = 15; }); ``` ```php isSMTP(); $phpmailer->XMailer = 'krumaxMailer 1.0'; $phpmailer->Host = 'mta.krumax.cz'; $phpmailer->Port = 587; $phpmailer->Username = 'postmaster@us1.krumax.cz'; $phpmailer->Password = 'qwerty'; $phpmailer->SMTPAuth = true; $phpmailer->SMTPSecure = 'tls'; $phpmailer->SMTPAutoTLS = true; $phpmailer->SMTPOptions = [ 'ssl' => [ 'allow_self_signed' => true, ], ]; $phpmailer->From = 'no-reply@us1.krumax.cz'; // $phpmailer->FromName = 'Support team US1'; // $phpmailer->Hostname = 'us1.krumax.cz'; // $phpmailer->Encoding = 'quoted-printable'; // $phpmailer->Sender = 'bounce@us1.krumax.cz'; // $phpmailer->Timeout = 15; }); ``` 2. Create file for test send mail `/send-mail.php` ```php , " ]; if (wp_mail("$toName <{$to}>", $subject, $message, $headers)) { echo "Success"; } else { echo "Failed"; } ``` 3. Open URL http://us1.krumax.cz/send-mail.php ## Send mail from pod in k3s (use Postfix). 1. Install postfix: `apt-get install -y postfix` 2. Set config: ```bash postconf -e 'myhostname = mta.krumax.cz' postconf -e 'mydomain = us1.krumax.cz' postconf -e 'myorigin = $mydomain' ``` 3. Create file `test.mail`: ``` From: Support team US1 To: Maksym Krugol Subject: Test delivery (postfix) Date: Wed, 17 Sep 2025 10:53:13 +0200 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Hi! Test with /usr/sbin/sendmail. ``` 4. Send mail: `sendmail -v -oi -t -f 'no-reply@us1.krumax.cz' < test.mail` ## Send mail from pod in k3s (use msmtp). 1. Install msmtp: `apt-get install -y msmtp msmtp-mta ca-certificates` 2. Set config `/etc/msmtprc`: ``` defaults auth on tls on tls_starttls on tls_trust_file /etc/ssl/certs/ca-certificates.crt logfile /var/log/msmtp.log account default host mta.krumax.cz port 587 from no-reply@us1.krumax.cz user postmaster@us1.krumax.cz password qwerty ``` 3. Create file `test.mail`: ``` From: Support team US1 To: Maksym Krugol Subject: Test delivery (msmtp) Date: Wed, 17 Sep 2025 10:53:13 +0200 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Hi! Test with msmtp/sendmail. ``` 4. Send mail: `sendmail -v -oi -t -f 'no-reply@us1.krumax.cz' < test.mail`