When mail from your own server lands in spam, the cause is almost always one of a short list of technical problems: a missing reverse DNS record, a hostname that does not match, missing authentication records, or an IP address with a poor reputation. Content matters much less than most people think. In this tutorial you will check each of these points on a Postfix server running Ubuntu 24.04, fix what is wrong, and confirm the result with a real test message.
Prerequisites
To follow this tutorial, you need:
- A server running Ubuntu 24.04 LTS with Postfix installed and able to send mail, for example a CubePath VPS.
- A non-root user with
sudoprivileges. - A domain you control, with access to its DNS zone. This guide uses
your_domainfor the domain,mail.your_domainfor the server hostname and203.0.113.10foryour_server_ip. - A Gmail or Outlook mailbox to receive test messages.
- The
digcommand (sudo apt install bind9-dnsutils).
Step 1 - Checking that the server can send on port 25
Servers deliver mail to each other on TCP port 25. Many providers block outgoing connections on that port by default to protect the reputation of their IP ranges, and a blocked port shows up as mail stuck in the queue rather than in spam. Test a connection to Gmail's mail servers:
nc -vz -w 5 gmail-smtp-in.l.google.com 25
Connection to gmail-smtp-in.l.google.com (142.250.153.27) 25 port [tcp/smtp] succeeded!
A timeout means outgoing port 25 is blocked. On CubePath, outgoing port 25 is closed by default. To send mail directly from your server, open a support ticket describing what the server sends (for example, transactional mail from your application or a company mail server); the team reviews each request.
Sending is enabled for a specific IP address. If your server has more than one IPv4 address, make Postfix send from the enabled one, which should also be the address with the reverse DNS record from Step 2. Add this line to /etc/postfix/main.cf:
smtp_bind_address = 203.0.113.10
Then reload Postfix with sudo systemctl reload postfix.
Step 2 - Setting a matching hostname and reverse DNS
Receiving servers check three names, and they should all be the same fully qualified name:
- The HELO/EHLO name your server announces, which Postfix takes from
myhostname. - The A record of that name, which must point to your server's IP.
- The PTR record (reverse DNS) of your server's IP, which must point back to that name.
A missing or generic PTR record (such as 203-0-113-10.provider.net) is the most common reason for rejections and spam placement, and Gmail and Outlook treat it as a hard requirement.
Set the system hostname and check what Postfix uses:
sudo hostnamectl set-hostname mail.your_domain
postconf myhostname
myhostname = mail.your_domain
If myhostname shows something else, set it explicitly:
sudo postconf -e 'myhostname = mail.your_domain'
sudo systemctl reload postfix
Create an A record for mail.your_domain pointing to 203.0.113.10 in your DNS zone. Then set the PTR record for the IP: on CubePath, edit the Reverse DNS field of the IP address in the panel and enter mail.your_domain. The full procedure is in How to Configure Reverse DNS (PTR Records).
Verify that both directions match:
dig +short A mail.your_domain
dig +short -x 203.0.113.10
203.0.113.10
mail.your_domain.
If the server sends over IPv6, do the same for its IPv6 address with an AAAA record and a PTR record. Gmail applies stricter checks to mail arriving over IPv6. If you cannot set up IPv6 reverse DNS, make Postfix send over IPv4 only with sudo postconf -e 'inet_protocols = ipv4'.
Step 3 - Publishing SPF, DKIM and DMARC
Gmail, Yahoo and Microsoft require authentication. Every sender needs SPF or DKIM, and senders of more than a few thousand messages a day need all three, with DMARC aligned to the From domain. Check what your domain publishes today:
dig +short TXT your_domain | grep spf1
dig +short TXT _dmarc.your_domain
"v=spf1 ip4:203.0.113.10 -all"
"v=DMARC1; p=none; rua=mailto:dmarc-reports@your_domain"
If either is empty, follow How to Configure SPF and DMARC Records. If your messages are not DKIM signed yet, follow How to Set Up DKIM with OpenDKIM and Postfix. DKIM is the one that matters most in practice, because it survives forwarding.
Step 4 - Enabling TLS for outgoing mail
Gmail marks messages received without encryption with a red padlock, and unencrypted delivery counts against you. Postfix on Ubuntu 24.04 uses opportunistic TLS for outgoing mail by default. Confirm it:
postconf smtp_tls_security_level
smtp_tls_security_level = may
If the value is empty or none, enable it:
sudo postconf -e 'smtp_tls_security_level = may'
sudo systemctl reload postfix
For incoming connections, Postfix should present a valid certificate for mail.your_domain rather than the default self-signed "snakeoil" one. If you have a Let's Encrypt certificate for that name, point Postfix to it:
sudo postconf -e 'smtpd_tls_cert_file = /etc/letsencrypt/live/mail.your_domain/fullchain.pem'
sudo postconf -e 'smtpd_tls_key_file = /etc/letsencrypt/live/mail.your_domain/privkey.pem'
sudo postconf -e 'smtpd_tls_security_level = may'
sudo systemctl reload postfix
After sending a message, the log shows whether the connection to the receiver was encrypted:
sudo grep "TLS connection established to" /var/log/mail.log | tail -n 3
postfix/smtp[5123]: Trusted TLS connection established to gmail-smtp-in.l.google.com[142.250.153.27]:25: TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
Step 5 - Checking IP and domain blocklists
If your IP address was used by a spammer before it was assigned to you, or your server was compromised, it may be listed on a DNS blocklist. Check it with a multi-list lookup service such as MXToolbox (Blacklist Check) or multirbl.valli.org by entering 203.0.113.10.
You can also query the Spamhaus ZEN list from the command line. The query uses the IP with its octets reversed:
dig +short 10.113.0.203.zen.spamhaus.org
No output means the IP is not listed. An answer in 127.0.0.x means it is listed. If you get 127.255.255.254 or a similar 127.255.255.x answer, Spamhaus refused the query because it came through a public resolver; use the web lookup at check.spamhaus.org instead.
If the IP is listed:
- Find and stop the cause first: an open relay, a compromised account or a vulnerable web form. Check
sudo postconf mynetworksincludes only127.0.0.0/8and[::1]/128, and look for large bursts in/var/log/mail.log. - Request removal through the blocklist's own delisting page. Most lists delist automatically once the spam stops.
Step 6 - Sending a test message and reading the result
Send a test message to a Gmail address, and optionally to a scoring service such as mail-tester.com, which gives you a one-time address and a detailed report. Replace the addresses:
printf 'From: Admin <admin@your_domain>\nTo: [email protected]\nSubject: Deliverability test\n\nThis is a plain test message from the server.\n' | sudo sendmail -f admin@your_domain [email protected]
In Gmail, open the message and choose Show original. The summary at the top should show:
SPF: PASS with IP 203.0.113.10
DKIM: 'PASS' with domain your_domain
DMARC: 'PASS'
Also check the Received headers and the padlock icon for TLS. If anything fails, the header tells you which check, and the previous steps tell you how to fix it.
Step 7 - Building and protecting your reputation
With the technical checks passing, placement depends on reputation: how recipients react to your mail over time.
- Warm up a new IP. A fresh IP that suddenly sends thousands of messages looks like a spammer. Start with low volumes to engaged recipients and increase gradually over a few weeks.
- Send only to people who asked for it. Never buy lists. Remove addresses that bounce, and stop mailing people who never open your messages.
- Make unsubscribing easy for bulk mail. Newsletters and marketing mail need
List-UnsubscribeandList-Unsubscribe-Post: List-Unsubscribe=One-Clickheaders, which Gmail and Yahoo require from bulk senders. Most mailing list software adds them for you. - Keep the spam complaint rate low. Gmail expects it below 0.1% and starts filtering heavily above 0.3%.
- Monitor. Register your domain in Google Postmaster Tools to see your spam rate and reputation at Gmail, and your IP in Microsoft SNDS for Outlook.com.
- Keep transactional and marketing mail apart. Send newsletters from a subdomain such as
news.your_domainor through a dedicated provider, so a bad campaign does not affect password reset mail.
Content still plays a role at the margin: send a plain text part together with HTML, avoid link shorteners and messages that are a single large image, and make the From name and address consistent.
Troubleshooting
- Mail stays in the queue with
Connection timed outto port 25. Outgoing port 25 is blocked. See Step 1. Check the queue withmailq. - Gmail rejects with
550-5.7.25 ... PTR record ... does not match. The PTR record is missing or does not match the sending hostname, or mail is leaving over IPv6 without reverse DNS. Revisit Step 2. - Gmail rejects with
550-5.7.26 ... unauthenticated. The message failed SPF and DKIM, or failed DMARC alignment. Check the headers of a test message and fix the failing record. - Outlook.com rejects with
S3150or similar block codes. The IP is on Microsoft's internal blocklist. Use the Microsoft sender support delisting form and enroll in SNDS.
Conclusion
You checked the network path, aligned the server's hostname with its A and PTR records, confirmed SPF, DKIM and DMARC, enabled TLS and ruled out blocklists, which covers almost every technical reason for spam placement. From here, deliverability depends on sending wanted mail at a steady volume. As next steps, filter incoming spam with SpamAssassin and watch your Gmail reputation in Google Postmaster Tools over the next few weeks.
