Docs / Postfix

Postfix relayhost: send through an SMTP relay

Postfix on a server is usually there for mail that programs send: cron, monitoring, a website calling sendmail. Delivered directly, that mail leaves from the server's IP with no history and no DKIM, and the big mailbox providers meet it with their filters. The relayhost setting hands all outgoing mail to the Postwing relay instead: the relay signs it with your domain's DKIM key, and Postfix only has to log in and pass messages on.

✓
You can get them on the token management page. For security reasons, a token is shown only once — at the moment it is created.

SMTP connection settings

SettingValue
SMTP hostsmtp.postwing.app
Port587
EncryptionSTARTTLS (the connection is upgraded to TLS before login)
UsernameThe login of an SMTP token for your domain
PasswordThe password of that token — shown once, when the token is created
ℹ
Every mode is also available on a high port: 8465 (SSL/TLS), 8587 (STARTTLS) and 8025 (plain). Many hosting providers and clouds block outbound 25, 465 and 587 — if the connection times out, switch to the matching high port.

Packages

Postfix authenticates through Cyrus SASL, and the PLAIN mechanism ships in a separate package. Without it authentication never starts and the log says No worthy mechs found:

bash
# Debian, Ubuntu: SASL modules including PLAIN
sudo apt install postfix libsasl2-modules

# RHEL, AlmaLinux, Rocky
sudo dnf install postfix cyrus-sasl-plain

Relay all mail

Add to /etc/postfix/main.cf:

/etc/postfix/main.cf
# /etc/postfix/main.cf — send all outgoing mail through the relay
relayhost = [smtp.postwing.app]:587

smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
# PLAIN sends the password in the clear, so allow it only inside TLS
smtp_sasl_tls_security_options = noanonymous

smtp_tls_security_level = encrypt
ParameterWhat it does
relayhost Where to hand all mail for other domains. The brackets turn off the MX lookup; :587 is the submission port with STARTTLS.
smtp_sasl_auth_enableTurns on client-side SMTP authentication.
smtp_sasl_password_mapsThe table holding a login and password per relay.
smtp_sasl_tls_security_options Lifts the ban on plaintext mechanisms inside TLS. Without it Postfix refuses to use PLAIN.
smtp_tls_security_level = encrypt Never send unencrypted: if STARTTLS fails, the message stays queued and the password is never sent in the clear.

Credentials

Create /etc/postfix/sasl_passwd. The key at the start of the line must match relayhost exactly, brackets and port included:

/etc/postfix/sasl_passwd
# /etc/postfix/sasl_passwd
# the key must match relayhost exactly, brackets and port included
[smtp.postwing.app]:587    token-login@your-domain.com:your-token-password

Make the file readable by root only, build the index and reload. Run postmap after every edit, or Postfix keeps reading the old .db:

bash
sudo chmod 600 /etc/postfix/sasl_passwd
sudo postmap /etc/postfix/sasl_passwd     # builds sasl_passwd.db
sudo postfix check
sudo systemctl reload postfix
ℹ
The examples use hash: tables. If postconf -m does not list it, use the type from postconf default_database_type, such as lmdb:, both in main.cf and in postmap lmdb:/etc/postfix/sasl_passwd.

Port 465

Implicit TLS on port 465 needs smtp_tls_wrappermode (Postfix 3.0 and later). Without it Postfix waits for a plaintext greeting that never comes and gives up on a timeout:

properties
# /etc/postfix/main.cf — port 465, TLS from the first byte
relayhost = [smtp.postwing.app]:465
smtp_tls_wrappermode = yes
smtp_tls_security_level = encrypt

# /etc/postfix/sasl_passwd — the key uses :465 too
[smtp.postwing.app]:465    token-login@your-domain.com:your-token-password

Relay one domain only

If the server hosts several sites or its own mail and only your verified domain should go through Postwing, leave relayhost empty and pick the relay by sender. Postfix looks the envelope sender up in full first, then by @domain:

/etc/postfix/main.cf
# /etc/postfix/main.cf — relay only mail from your-domain.com
# no relayhost: everything else is delivered directly, as before
sender_dependent_relayhost_maps = hash:/etc/postfix/sender_relay

smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_tls_security_options = noanonymous

# TLS is mandatory for the relay only, opportunistic elsewhere
smtp_tls_security_level = may
smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
# /etc/postfix/sender_relay
@your-domain.com           [smtp.postwing.app]:587

# /etc/postfix/tls_policy
[smtp.postwing.app]:587    encrypt

# /etc/postfix/sasl_passwd
[smtp.postwing.app]:587    token-login@your-domain.com:your-token-password
bash
sudo postmap /etc/postfix/sender_relay
sudo postmap /etc/postfix/tls_policy
sudo postmap /etc/postfix/sasl_passwd
sudo systemctl reload postfix

Credentials are still looked up by the relay's address, so smtp_sender_dependent_authentication is not needed here; it is for giving different senders different credentials. If you already route this domain with transport_maps, note that it takes precedence over sender_dependent_relayhost_maps.

Authentication: AUTH PLAIN only

The relay advertises a single mechanism, AUTH PLAIN. Postfix chooses from what it supports, what the server advertises and what smtp_sasl_mechanism_filter lets through, so nothing extra is needed. Two things can get in the way: the default smtp_sasl_security_options (noplaintext), and a leftover smtp_sasl_mechanism_filter = login from another provider.

Send a test email

Send from an address on your verified domain. The address after -f becomes the envelope sender, and that is what the relay checks:

bash
# Test message: the sender must be on your verified domain
printf 'From: noreply@your-domain.com\nTo: you@example.com\nSubject: Postfix relay test\n\nHello from Postfix\n' \
  | sendmail -f noreply@your-domain.com you@example.com

mailq                                  # an empty queue means it left
sudo journalctl -t postfix/smtp -f     # or /var/log/mail.log, /var/log/maillog

A successful hand-off looks like this in the log: relay= names the relay and status=sent means the relay accepted the message. What happened next, including the recipient server's reply, is in the delivery log in the dashboard.

postfix/smtp[2817]: 4F1A2C0D3E: to=<you@example.com>,
  relay=smtp.postwing.app[…]:587, delay=0.8, dsn=2.0.0, status=sent (250 …)

Troubleshooting

Log messageCause and fix
SASL authentication failure: No worthy mechs foundsmtp_sasl_tls_security_options = noanonymous is missing, or libsasl2-modules (cyrus-sasl-plain) is not installed.
SASL authentication failed; server … said: 535 5.7.8 Wrong token login or password. Check the line in sasl_passwd and rerun postmap. More on error 535 .
550 relaying denied Postfix connected without logging in: the sasl_passwd key does not match relayhost (brackets, port), or smtp_sasl_auth_enable is off. Relay refusals explained .
550 from must be equal to … The envelope sender is not on your verified domain, most often root@your-hostname. Use sender_dependent_relayhost_maps or smtp_generic_maps.
550 not relaying to your domain, required until verified The domain is not verified yet; until it is, mail can only go to addresses on that same domain.
timed out while receiving the initial server greetingrelayhost uses port 465 but smtp_tls_wrappermode is off.
connect to smtp.postwing.app…: Connection timed out Your host blocks the outbound port. Use 8587 or 8465, and change the port in both relayhost and sasl_passwd.
550 hourly limit exceeded The plan's hourly limit is used up. Postfix treats a 5xx reply as permanent and bounces the message back to the sender, so keep an eye on usage on the domain page.

Frequently asked questions

Why the square brackets around the host in relayhost?

They tell Postfix not to look up MX records for that name and to connect to the host itself. Without them Postfix queries the domain's MX and may go somewhere else. The key in sasl_passwd must be written the same way, brackets and port included, or the credentials are never found.

What does "SASL authentication failure: No worthy mechs found" mean?

Postfix found no authentication mechanism it is allowed to use. Our relay offers PLAIN only, and the default smtp_sasl_security_options forbids plaintext mechanisms. Set smtp_sasl_tls_security_options = noanonymous together with mandatory TLS. The same error appears when libsasl2-modules (cyrus-sasl-plain on RHEL) is not installed.

Do I need AUTH LOGIN or smtp_sasl_mechanism_filter?

No. The relay accepts AUTH PLAIN only, and Postfix picks it from what the server advertises. If an old smtp_sasl_mechanism_filter = login is still in the configuration, remove it or add plain: when the lists have nothing in common, authentication fails.

How do I relay mail for one domain only?

Leave relayhost empty and set sender_dependent_relayhost_maps with an entry @your-domain.com → [relay]:587. Mail whose envelope sender is on that domain goes through the relay; Postfix delivers the rest directly. Use smtp_tls_policy_maps to make TLS mandatory for the relay alone.

Do I need OpenDKIM or another signing milter?

Not for a domain verified in the dashboard: the relay signs it with DKIM, and SPF and DMARC are published in the delegated zone. If OpenDKIM already signs that domain, messages arrive with two signatures. That is not an error, but it is a second key to maintain for nothing.

Why is mail from cron and root refused?

System mail is sent as root@your-hostname. The relay accepts mail from verified domains only and answers "550 from must be equal to …". Relay just your own domain (sender_dependent_relayhost_maps) or rewrite the addresses with smtp_generic_maps.

Next steps