
WordPress email failures can feel random. Password resets never arrive. WooCommerce receipts land in spam. Contact form messages disappear.
The cause is usually consistent. PHP’s default mail() hands messages to a local MTA. Many VPS installs either have no outbound mail path, or they send with a weak identity (no aligned SPF/DKIM/DMARC).
This guide fixes that with a Postfix SMTP relay Ubuntu configuration on your VPS. Postfix will submit mail through a trusted upstream SMTP provider using authenticated TLS. WordPress keeps calling the local sendmail interface like it always has.
You’ll verify delivery with logs and real test messages. You’ll also cover the common failure modes behind “it sent” with nothing delivered.
What you’ll build (and what you won’t)
- Build: Ubuntu + Postfix configured as a relay client (a “smart host” setup) that sends outbound mail via an authenticated SMTP provider.
- Build: Clean sender identity (
From:) rewriting where needed, plus TLS and sane defaults. - Verify: Submission to the provider, queue behavior, and WordPress end-to-end mail delivery.
- Not building: A full inbound mail server. Your VPS will not host mailboxes.
If you want a full mail relay build with rate limits and inbound considerations, see this SMTP relay tutorial.
Here, the goal is simple: get WordPress outbound mail delivered reliably.
Prerequisites (5 minutes)
- An Ubuntu server (22.04 LTS or 24.04 LTS) with root or sudo access.
- A domain you control (example:
example.com). - An SMTP provider account (Mailgun, SES, SendGrid, Postmark, or your transactional provider). You need: SMTP hostname, port, username, password.
- WordPress running on the same VPS (Nginx/Apache, PHP-FPM, etc.).
If you need infrastructure first, start with a HostMyCode VPS.
If you want OS updates and baseline hardening handled for you, managed VPS hosting is often the better option for busy WordPress site owners.
Step 1: Confirm WordPress is failing (and collect a baseline)
Don’t change anything yet. First, reproduce the issue. Then capture enough evidence to confirm the fix later.
-
Trigger a WordPress email. For example: request a password reset for a test user.
-
Check your server mail log. On Ubuntu, Postfix logs to
/var/log/mail.log:sudo tail -n 200 /var/log/mail.logIf Postfix isn’t installed yet, you may see nothing mail-related. That’s still useful. It often explains why messages “vanish.”
-
Check whether a local MTA is present.
dpkg -l | egrep 'postfix|exim|sendmail' systemctl status postfix --no-pager
Typical baseline results:
- No MTA installed: WordPress reports success, but nothing actually transmits.
- Postfix installed with defaults: mail queues, then bounces due to blocked outbound port 25 or poor sender reputation.
- Mail leaves the server but lands in spam because SPF/DKIM/DMARC don’t align with the visible From domain.
Step 2: Install Postfix and required packages
Install Postfix and the SASL modules it uses to authenticate to your SMTP provider.
sudo apt update
sudo apt install -y postfix libsasl2-modules ca-certificates bsd-mailx
During installation you may be prompted:
- General type of mail configuration: choose
Internet Site(we’ll override relay behavior next). - System mail name: set to your domain (example:
example.com).
If you don’t see prompts, that’s fine. You’ll set the final values in main.cf.
Step 3: Configure Postfix to relay through your SMTP provider
Edit Postfix’s main config:
sudo nano /etc/postfix/main.cf
Add (or replace) these settings. Keep the structure, but change the example values to match your domain and provider.
# Identity
myhostname = mail.example.com
mydomain = example.com
myorigin = $mydomain
# Listen locally only (we are not accepting inbound SMTP from the internet)
inet_interfaces = loopback-only
inet_protocols = all
# Relay everything via your SMTP provider (smart host)
relayhost = [smtp.provider.tld]:587
# TLS for outbound SMTP
smtp_tls_security_level = encrypt
smtp_tls_loglevel = 1
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
# SMTP AUTH
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_tls_security_options = noanonymous
# Sensible queue/timeouts
smtp_connect_timeout = 30s
smtp_helo_timeout = 30s
smtp_mail_timeout = 60s
smtp_rcpt_timeout = 60s
# Avoid leaking internal hostnames
smtp_header_checks = regexp:/etc/postfix/smtp_header_checks
Choose the right port. Most providers use 587 (submission) or 465 (implicit TLS).
If your provider requires 465, change relayhost and set:
relayhost = [smtp.provider.tld]:465
smtp_tls_wrappermode = yes
About inet_interfaces: keep loopback-only on purpose. It prevents the VPS from accepting SMTP from the internet.
WordPress only needs local delivery to Postfix via sendmail.
Step 4: Add SMTP credentials securely
Create /etc/postfix/sasl_passwd with your provider credentials. Use brackets around the host so the entry matches relayhost exactly.
sudo nano /etc/postfix/sasl_passwd
[smtp.provider.tld]:587 USERNAME:PASSWORD
Lock down permissions. Then compile the hash map that Postfix reads:
sudo chmod 600 /etc/postfix/sasl_passwd
sudo postmap /etc/postfix/sasl_passwd
sudo ls -l /etc/postfix/sasl_passwd*
You should see sasl_passwd and sasl_passwd.db, both readable only by root.
Step 5: Fix common WordPress “From” problems (header rewriting)
WordPress often sends from defaults like wordpress@your-vps-hostname or www-data@localhost. That breaks DMARC alignment and raises spam scores quickly.
The fixes here are straightforward:
- Strip internal hostnames from headers that shouldn’t leak.
- Optionally rewrite the envelope sender to something valid on your domain.
5.1 Add header checks to clean up obvious bad headers
Create the header checks file:
sudo nano /etc/postfix/smtp_header_checks
/^Received:.*\(localhost\)/ IGNORE
/^X-PHP-Originating-Script:/ IGNORE
Compile it:
sudo postmap /etc/postfix/smtp_header_checks
5.2 (Optional) Rewrite envelope sender to a valid domain
If messages go out with a junk envelope sender, bounces become hard to track. Complaints also get messier.
A simple, safe default is to force system senders onto a real address at your domain.
Add to /etc/postfix/main.cf:
sender_canonical_maps = regexp:/etc/postfix/sender_canonical
Create the map:
sudo nano /etc/postfix/sender_canonical
/^www-data@.*/ no-reply@example.com
/^root@.*/ no-reply@example.com
Then reload Postfix after you validate the config in the next step.
Step 6: Validate Postfix config and restart safely
Run a quick syntax check before you restart anything:
sudo postfix check
If it returns clean, restart and confirm Postfix is healthy:
sudo systemctl restart postfix
sudo systemctl status postfix --no-pager
Now confirm Postfix only listens locally:
sudo ss -ltnp | grep -E ':25\b|:587\b|:465\b' || true
Expected: you might see Postfix on 127.0.0.1:25. You should not see 0.0.0.0:25 or a public IP listener.
Step 7: Send a test email from the VPS and verify logs
Send a simple outbound message:
echo "Postfix relay test from $(hostname)" | mail -s "Postfix relay test" you@your-inbox.tld
While you send it, watch the mail log:
sudo tail -f /var/log/mail.log
In the output, you want to see:
relay=smtp.provider.tldstatus=sent- TLS details (often
Trusted TLS connection established)
If you see authentication failed, trust the log. Either the credentials are wrong, or your provider expects an API key as the password.
Update /etc/postfix/sasl_passwd. Run postmap again. Then restart Postfix.
Step 8: Connect WordPress to Postfix correctly (without plugins)
If WordPress and PHP can call /usr/sbin/sendmail, you don’t need an SMTP plugin. Postfix is your transport layer. WordPress stays unchanged.
Confirm PHP isn’t disabling mail() and that it has a sendmail path:
php -i | grep -E '^disable_functions|sendmail_path'
Typical good output:
sendmail_path => /usr/sbin/sendmail -t -i
Trigger another real WordPress email (password reset, WooCommerce order, or a form submission). Then verify it actually left the box:
sudo grep -i "status=sent" /var/log/mail.log | tail -n 20
If you want more visibility during setup, use a mail logging plugin temporarily. Remove it once you’re satisfied.
Those logs can include sensitive recipient addresses.
Step 9: Fix deliverability the right way: SPF, DKIM, DMARC, and rDNS
Relaying through a provider helps quickly, but authentication still matters. In 2026, mailbox providers are unforgiving about missing or misaligned identity.
The rule you can rely on: the From domain your users see must authenticate with SPF and DKIM, and DMARC should pass.
- If your SMTP provider signs DKIM for your domain, enable it in the provider dashboard and publish their DKIM TXT records.
- Publish SPF to authorize the provider.
- Publish DMARC to tell receivers what to do if auth fails.
Follow HostMyCode’s step-by-step DNS guide: set up DKIM, SPF, and DMARC for a domain.
If you also send mail directly from the VPS for any reason (not recommended for WordPress transactional mail), reverse DNS matters too: configure rDNS on a VPS.
Step 10: Add lightweight monitoring for mail failures
When email breaks quietly, you lose orders and create support work. Two quick checks catch most problems early.
-
Queue check:
mailqIf messages start piling up, your provider is rejecting connections, throttling, or auth is failing.
-
Error scan:
sudo egrep -i "(warning|error|deferred|bounced|authentication failed)" /var/log/mail.log | tail -n 50
For wider server visibility (CPU steal, disk pressure, or network drops that can interrupt SMTP), add basic monitoring.
This guide is a solid baseline: build alerts with Netdata + uptime checks.
Troubleshooting: the failures you’ll actually see
-
Mail stuck in queue with “Connection timed out”.
Confirm the provider hostname and port. Many networks block outbound 25, so stick to 587 or 465. Test connectivity with:sudo apt install -y netcat-openbsd nc -vz smtp.provider.tld 587 nc -vz smtp.provider.tld 465 -
“SASL authentication failed” in
/var/log/mail.log.
Re-check/etc/postfix/sasl_passwd. Then runpostmapand restart Postfix. -
Messages send, but land in spam.
Open the received headers and look for SPF/DKIM/DMARC results. Fix DNS records. Also make sure the WordPress From domain matches the authenticated domain. -
WordPress uses a weird From address despite settings.
Some plugins override mail headers. Disable mail-related plugins temporarily and test again. If it keeps happening, enforce canonical sender mapping (Step 5.2). -
Postfix is listening publicly on port 25.
Setinet_interfaces = loopback-only, restart Postfix, and re-check withss -ltnp. Don’t expose SMTP unless you intend to run an inbound mail service.
Security notes that prevent expensive mistakes
Two choices here do most of the security work:
- Loopback-only SMTP listener keeps remote clients from using your Postfix service.
- Root-only credential files prevent SMTP credentials from leaking through the web stack.
Also make sure your firewall rules match your intent.
If you haven’t done it yet, follow this UFW firewall tutorial and keep inbound ports minimal.
Summary: your WordPress emails should be reliable now
You installed Postfix on Ubuntu. You configured it as a smart-host relay. You enabled authenticated TLS and verified delivery in /var/log/mail.log.
WordPress continues sending mail normally. Your VPS now hands messages to a provider designed for transactional delivery.
If you’re planning to move WordPress onto a VPS, or you want more predictable performance than shared hosting, HostMyCode can handle the infrastructure side.
Start with a HostMyCode VPS, or choose managed VPS hosting if you want patching and baseline ops handled for you.
If WordPress email reliability is affecting signups or orders, run it on infrastructure you can control and observe. A HostMyCode VPS gives you clean networking, full mail logs, and the ability to enforce safe defaults like loopback-only Postfix.
If you don’t want to spend your time on OS updates, Postfix maintenance, or monitoring, managed VPS hosting keeps the server side steady while you focus on the site.
FAQ
Do I still need a WordPress SMTP plugin after setting up Postfix?
Usually no. WordPress can keep using mail() and the local sendmail binary, and Postfix handles the relay. Use a plugin only if you need per-site SMTP routing or detailed in-dashboard logging.
Which “From” address should my WordPress site use?
Use an address on a domain you authenticate with SPF/DKIM/DMARC, like no-reply@example.com. Avoid wordpress@hostname and avoid mismatching domains (that breaks DMARC alignment).
Can I run this on the same VPS as my WordPress site?
Yes. This setup is designed for that. Postfix listens only on loopback, so it doesn’t expose a public SMTP service.
How do I confirm Postfix is actually using my provider and not sending directly?
Check /var/log/mail.log for relay=smtp.provider.tld and status=sent. If you see direct delivery attempts to recipient MX hosts, your relayhost setting is missing or mis-typed.
What’s the fastest way to catch failures before customers do?
Watch for queue growth (mailq) and scan mail logs for deferrals. Pair that with basic VPS monitoring and uptime checks so you notice network and disk issues early.