How to send email from a VPS through an SMTP relay
Send your server's mail (alerts, cron output, app email) through an SMTP relay on port 587 with Postfix, so it's delivered without running a full mail server.
Tested on Debian 13 Stable
Before you start
- A server running Ubuntu or Debian (AlmaLinux and Rocky work with dnf instead of apt)
- Root or a user with sudo
- An account with an SMTP relay or email provider and its SMTP host and login
- A domain you can add DNS records to
To send email from a VPS, hand it to an SMTP relay instead of delivering it yourself: install Postfix as a "satellite system", set relayhost = [smtp.your-relay.com]:587, give it the relay's username and password in /etc/postfix/sasl_passwd, and require TLS. Every program on the server that sends mail through sendmail or localhost:25 then goes through the relay.
A relay is any provider that accepts mail from you over an authenticated connection and delivers it: transactional email services, or the SMTP server of the mailbox provider you already use. They deliver from addresses with an established reputation, which is why mail sent this way reaches inboxes rather than spam folders. It also works when outbound port 25 is blocked, as it is on many VPS providers, because relays accept mail on ports 587 and 465.
We configured and checked this on Debian 13 (Postfix 3.10), including the queue and the log; our test relay was a hostname that doesn't exist, so the last step (actual delivery) depends on your provider's details.
What you need from the relay
From your relay's documentation or dashboard, note:
| Example | |
|---|---|
| SMTP host | smtp.relay.example |
| Port | 587 (STARTTLS) or 465 (TLS from the start) |
| Username | Often your account email, or a literal word like apikey |
| Password | An SMTP password or API key, not your account password where they're separate |
| Allowed sender | The domain or address you've verified with them, such as alerts@example.com |
Most relays require you to verify your sending domain by adding DNS records (SPF and DKIM). Do that in their dashboard first; it's what makes the mail trusted.
Install Postfix
sudo apt update
sudo apt install -y postfix libsasl2-modules mailutilsThe installer asks a few questions:
- General type of mail configuration: choose Satellite system.
- System mail name: your server's full name or your domain, for example
web-1.example.com. It's stored in/etc/mailnameand used for mail from local users likeroot. - If it asks for the SMTP relay host, enter
[smtp.relay.example]:587. You can also set it in the next step.
libsasl2-modules lets Postfix log in to the relay; mailutils gives you the mail command for testing. On AlmaLinux and Rocky Linux, install postfix cyrus-sasl-plain s-nail with dnf and edit the same settings with postconf.
Point Postfix at the relay
Set the relay and the login options. The square brackets tell Postfix to connect to that host directly rather than look up its MX records:
sudo postconf -e \
'relayhost = [smtp.relay.example]:587' \
'smtp_sasl_auth_enable = yes' \
'smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd' \
'smtp_sasl_security_options = noanonymous' \
'smtp_tls_security_level = encrypt' \
'inet_interfaces = loopback-only'What these do: log in with the password from a file, never without a login, refuse to send unless the connection is encrypted (so the password never crosses the network in clear), and accept mail only from the server itself, so you don't run an open relay.
For a relay on port 465 instead, use relayhost = [smtp.relay.example]:465 and add smtp_tls_wrappermode = yes.
Store the login, readable by root only, and build the lookup table Postfix reads:
echo '[smtp.relay.example]:587 USERNAME:PASSWORD' | sudo tee /etc/postfix/sasl_passwd >/dev/null
sudo chmod 600 /etc/postfix/sasl_passwd
sudo postmap /etc/postfix/sasl_passwdThe host and port must match relayhost exactly, brackets included. Run postmap again whenever you change the file.
Check the configuration and restart:
sudo postfix check
sudo systemctl restart postfixpostfix check prints nothing when all is well.
Send a test message
echo "Test from $(hostname)" | mail -s "Relay test" -r alerts@example.com you@example.net-r sets the sender. Use an address in the domain you verified with the relay; most relays reject anything else.
Check it worked
Watch Postfix's log while the message goes out:
sudo journalctl -t postfix/smtp -n 20A delivered message shows status=sent (250 ...) with the relay's name. Then look in the recipient's inbox, and open the message's headers ("Show original"): SPF: PASS and DKIM: PASS mean the domain setup is right.
Messages that couldn't be sent wait in the queue and are retried:
mailqUse it from your apps
- Anything that calls
sendmail(cron's output,mail, PHP'smail(), Netdata alerts,unattended-upgradesreports) now goes through the relay with no further setup. - Apps with their own SMTP settings can use
localhost, port25, no login and no TLS, and let Postfix handle the relay; or skip Postfix and give the app the relay's details directly.
To make mail for root (cron errors, system alerts) reach you, add a forward:
echo 'root: you@example.net' | sudo tee -a /etc/aliases
sudo newaliasesTroubleshooting
status=deferred (Host or domain name not found ...). The relay's hostname is wrong in relayhost. Fix it, update sasl_passwd to match, postmap it, and sudo postqueue -f to retry the queue.
SASL authentication failed or 535 Authentication credentials invalid. Wrong username or password, or the line in sasl_passwd doesn't match relayhost exactly. Check, postmap again, sudo systemctl reload postfix.
no mechanism available in the log. The SASL modules aren't installed: sudo apt install libsasl2-modules.
Sender address rejected or 550 ... not verified. The relay doesn't accept that From. Send from your verified domain (-r for mail; the "from" setting in your app). To rewrite root@web-1.example.com for system mail, see Postfix's smtp_generic_maps.
connect to smtp.relay.example[...]:25: Connection timed out. Postfix is using port 25 because relayhost has no port. Add :587.
To clear test messages out of the queue: sudo postsuper -d ALL.
Next steps
- Make sure your domain points where you think it does: point a domain at your VPS.
- Have Netdata email its alerts: monitor with Netdata.
Doing it on VPSNine
New VPSNine servers can't send on outbound port 25, which is why this tutorial uses 587. Relays on 587 and 465 work out of the box. If you need to run your own mail server instead, read Sending email: port 25 and set reverse DNS before you ask us to open it. Runs on Debian 13 and every other image, on all plans.