From 6475524d23ca130beb01994289e7adbd5bcc667f Mon Sep 17 00:00:00 2001 From: Dominik Polakovics Date: Sun, 23 Nov 2025 11:29:07 +0100 Subject: [PATCH] fix: amz postfix setup --- hosts/amzebs-01/EMAIL_SETUP.md | 141 ++++++++++++++++++++++++++-- hosts/amzebs-01/modules/postfix.nix | 25 +++++ 2 files changed, 156 insertions(+), 10 deletions(-) diff --git a/hosts/amzebs-01/EMAIL_SETUP.md b/hosts/amzebs-01/EMAIL_SETUP.md index 63849a6..72aadfb 100644 --- a/hosts/amzebs-01/EMAIL_SETUP.md +++ b/hosts/amzebs-01/EMAIL_SETUP.md @@ -157,7 +157,88 @@ ls -la /var/lib/rspamd/dkim/amz.at.amzebs-01.key ## DNS Configuration -Add the following DNS records to your `amz.at` domain: +Add the following DNS records to ensure proper email delivery and avoid spam classification. + +### Critical: PTR Record (Reverse DNS) + +**This is CRITICAL for email deliverability!** Without a proper PTR record, most mail servers will reject or spam your emails. + +#### What is a PTR Record? +A PTR (pointer) record is a reverse DNS entry that maps your IP address back to your hostname. Mail servers use this to verify you're a legitimate mail server. + +#### Required PTR Record +``` +IP Address: 23.88.38.1 +Points to: amzebs-01.amz.at +``` + +#### How to Configure PTR Record + +**Step 1: Contact Your Hosting Provider** + +PTR records MUST be configured through your hosting provider (e.g., Hetzner, OVH, AWS, etc.). You cannot set PTR records through your domain registrar. + +1. Log into your hosting provider's control panel +2. Find the "Reverse DNS" or "PTR Record" section +3. Set the PTR record for IP `23.88.38.1` to point to `amzebs-01.amz.at` + +**Common Provider Links:** +- **Hetzner**: Robot panel → IPs → Edit reverse DNS +- **OVH**: Network → IP → ... → Modify reverse +- **AWS EC2**: Select instance → Networking → Request reverse DNS + +**Step 2: Verify Forward DNS First** + +Before setting the PTR record, ensure your forward DNS is correct: + +```bash +# This should return 23.88.38.1 +dig +short amzebs-01.amz.at A +host amzebs-01.amz.at +``` + +**Step 3: Verify PTR Record** + +After configuring, verify the PTR record is working: + +```bash +# Method 1: Using dig +dig +short -x 23.88.38.1 + +# Method 2: Using host +host 23.88.38.1 + +# Method 3: Using nslookup +nslookup 23.88.38.1 +``` + +All commands should return: `amzebs-01.amz.at` + +**Step 4: Verify FCrDNS (Forward-Confirmed Reverse DNS)** + +This ensures forward and reverse DNS match properly: + +```bash +# Forward lookup +dig +short amzebs-01.amz.at +# Should output: 23.88.38.1 + +# Reverse lookup +dig +short -x 23.88.38.1 +# Should output: amzebs-01.amz.at. +``` + +If both work correctly, FCrDNS passes! ✓ + +**Why PTR Records Matter:** +- Gmail, Microsoft, Yahoo require valid PTR records +- Missing PTR = automatic spam classification or rejection +- Can add 5-10 points to spam score alone +- Required for professional email delivery + +### Domain DNS Records (amz.at) + +Add these records through your domain registrar's DNS management: #### SPF Record ``` @@ -242,17 +323,57 @@ journalctl -u postfix -f journalctl -u rspamd -f ``` -### Test DKIM Signature +### Test DKIM Signature and Deliverability -Send an email to a Gmail account or use an email testing service like: -- https://www.mail-tester.com/ -- https://mxtoolbox.com/emailhealth/ +Send an email to test your complete email configuration: -They will show you: -- If DKIM signature is valid -- If SPF passes -- If DMARC passes -- Your spam score +#### Email Testing Services +1. **Mail Tester** (https://www.mail-tester.com/) + - Provides a temporary email address + - Shows comprehensive spam score (0-10, higher is better) + - Checks DKIM, SPF, DMARC, PTR, blacklists, content + - **Target: 9/10 or higher** + +2. **MXToolbox Email Health** (https://mxtoolbox.com/emailhealth/) + - Comprehensive deliverability check + - Checks DNS records, blacklists, configuration + +3. **Google Admin Toolbox** (https://toolbox.googleapps.com/apps/messageheader/) + - Paste email headers to see how Gmail scored your email + - Shows SPF, DKIM, DMARC results + +#### What to Check +- ✓ DKIM signature is valid +- ✓ SPF passes +- ✓ DMARC passes +- ✓ PTR record (reverse DNS) matches +- ✓ Not on any blacklists +- ✓ Spam score < 2.0 (lower is better) + +#### Common Issues & Fixes + +**High Spam Score (> 5.0)** +- Check: PTR record configured correctly? (Critical!) +- Check: HELO name matches hostname? +- Check: All headers present (To:, From:, Subject:)? +- Check: IP not blacklisted? + +**Missing "To:" Header** +Your Laravel app must set a recipient. In your code: +```php +Mail::to('recipient@example.com') + ->send(new YourMailable()); +``` + +**HELO/EHLO Mismatch** +After applying this configuration, HELO should be `amzebs-01.amz.at`, not `localhost` + +**Check Current HELO Name** +```bash +# On the server +echo "HELO test" | nc localhost 25 +# Should see: 250 amzebs-01.amz.at +``` ## Verification Commands diff --git a/hosts/amzebs-01/modules/postfix.nix b/hosts/amzebs-01/modules/postfix.nix index ed4bca1..6c21698 100644 --- a/hosts/amzebs-01/modules/postfix.nix +++ b/hosts/amzebs-01/modules/postfix.nix @@ -4,12 +4,28 @@ , ... }: { + # Header checks file for validating email headers + environment.etc."postfix/header_checks".text = '' + # Warn about missing critical headers (but don't reject from localhost) + # These help identify misconfigured applications + /^$/ WARN Missing headers detected + ''; + services.postfix = { enable = true; hostname = "amzebs-01.amz.at"; domain = "amz.at"; config = { + # Explicitly set hostname to prevent "localhost" HELO issues + myhostname = "amzebs-01.amz.at"; + + # Set proper HELO name for outgoing SMTP connections + smtp_helo_name = "amzebs-01.amz.at"; + + # Professional SMTP banner (prevents appearing as default/misconfigured) + smtpd_banner = "$myhostname ESMTP"; + # Listen only on localhost for security # Laravel will send via localhost, no external access needed inet_interfaces = "loopback-only"; @@ -24,6 +40,15 @@ mailbox_size_limit = "202400000"; # ~200MB message_size_limit = "51200000"; # ~50MB + # Ensure proper header handling + # Reject mail that's missing critical headers + header_checks = "regexp:/etc/postfix/header_checks"; + + # Rate limiting to prevent spam-like behavior + # Allow reasonable sending rates for applications + smtpd_client_message_rate_limit = "100"; + smtpd_client_recipient_rate_limit = "200"; + # Milter configuration is handled automatically by rspamd.postfix.enable }; };