Configure Postfix to Use an External SMTP Server (SendGrid, Mailgun, Amazon SES)

An orange envelope icon with a white letter under a blue cloud on a light blue background, with the text ‘Postfix External SMTP Server.’

We may earn a referral fee at no additional cost to you when you shop through the links on this page.

Your Linux server needs to send transactional email (password resets, signup confirmations, monitoring alerts) without fighting reverse-DNS, SPF, DKIM, and DMARC configuration to make Gmail accept mail from your IP. The cleaner approach is to relay outbound mail through a dedicated transactional SMTP provider. This DevAnswers walkthrough configures Postfix on Ubuntu 22.04+ or Debian 12+ to relay through SendGrid, Mailgun, or Amazon SES, the three dominant transactional providers in 2026.

Prerequisites 

  • A Linux server running Ubuntu 22.04 / 24.04 / 26.04 LTS or Debian 12 / 13, with sudo access.
  • Outbound network access on port 587 (STARTTLS) or port 465 (TLS Wrapper). Most ISPs and cloud hosts block port 25 by default, so this guide does not use port 25.
  • An account with one of: SendGrid, Mailgun, or Amazon SES, with SMTP credentials generated.
  • Looking for Gmail relay instead? See our companion guide on configuring Postfix to use Gmail SMTP. Gmail uses a different authentication pattern (App Password + 2-Step Verification) and is covered there in detail.

Choose Your Provider 

The three providers in this guide share an almost-identical Postfix configuration pattern; the relay hostname, SMTP credentials, and (if you pick port 465 instead of 587) one extra TLS-wrapper directive are the only things that change. Pick based on volume, cost, and where your application is hosted.

  • SendGrid (Twilio SendGrid). Free tier 100 emails/day, paid tiers from $20/mo for 50,000/mo. Strong brand recognition. Good fit for SaaS and small-volume transactional.
  • Mailgun (Sinch-owned). Paid from around $35/mo after the trial. Developer-friendly API and good documentation. Popular with smaller dev teams.
  • Amazon SES. The cheapest at scale at $0.10 per 1,000 emails sent. Default for any application already hosted on AWS. Requires an AWS account, region selection, and awareness of the sandbox-mode restriction on new accounts.

Other providers worth knowing: Postmark (premium transactional-only with a deliverability focus), Resend (newer, popular with React and Next.js projects), and Brevo (formerly Sendinblue, popular for European SMB) all use the same Postfix SASL pattern; only the relayhost and credentials change. Microsoft 365 is intentionally not covered here because it now requires OAuth2 / modern auth for SMTP, which Postfix can only handle via an OAuth2-helper daemon (separate article).

If you haven’t picked a Linux host yet: some managed Linux hosting platforms include outbound SMTP as part of the platform, so you don’t configure Postfix at all. Cloudways bundles Elastic Email integration by default on its managed servers, with optional Mailgun or SendGrid add-ons if you’d rather use one of the providers below. Useful to know upfront, since this decision is easier to make BEFORE you provision the server than after you’ve installed Postfix.

Install Postfix on Ubuntu and Debian 

Install Postfix from the distro package, alongside mailutils (for the sendmail test command later) and libsasl2-modules (provides the PLAIN/LOGIN SASL mechanisms that SendGrid, Mailgun, and SES use; without it, authentication fails with “no worthy mechs found“):

Terminal
sudo apt update
sudo apt install -y postfix mailutils libsasl2-modules

The installer prompts you to pick a configuration type. For an outbound-only relay, choose Satellite system. Postfix sends all outbound mail to your smarthost and accepts no inbound. If you picked “Internet Site” or any other option during install by mistake, re-run the prompt:

Terminal
sudo dpkg-reconfigure postfix

Pick “Satellite system” this time. You will be asked for a system mail name; your server’s hostname is the typical answer.

Shared Relay Configuration in main.cf 

Open the Postfix main configuration file:

Terminal
sudo nano /etc/postfix/main.cf

Add this block at the bottom. Replace RELAYHOST_PLACEHOLDER with the per-provider value from the section below (the rest of the block is identical for all three providers):

/etc/postfix/main.cf
# External SMTP relay (replace RELAYHOST_PLACEHOLDER per provider)
relayhost = RELAYHOST_PLACEHOLDER

# SASL authentication (client side)
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

# TLS encryption (mandatory for the connection)
smtp_tls_security_level = encrypt
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt

Two directives are worth understanding. relayhost is the next-hop destination for non-local mail. Wrapping the hostname in square brackets is significant: it turns off MX lookups, so Postfix connects directly to the named host on the named port instead of asking DNS for the domain’s MX records. That’s what you want for a relay endpoint, since SMTP relay hostnames like smtp.sendgrid.net are not configured as mail-exchange servers for their own domains.

If you use port 465 (TLS Wrapper / implicit TLS) instead of 587 (STARTTLS): add one extra directive to the block above: smtp_tls_wrappermode = yes. Postfix needs to know to negotiate TLS at connection open rather than after a STARTTLS command. The shared block above is otherwise identical for both ports.

smtp_sasl_auth_enable = yes turns on client-side SASL authentication. The paired smtp_sasl_password_maps directive points at the credential table you’ll create in the next section. For TLS, smtp_tls_security_level = encrypt mandates encryption: Postfix refuses to send unless the server offers TLS. That’s the right default for an authenticated relay over a public network.

Now create the credential file at /etc/postfix/sasl_passwd. Add a single line in the format [host]:port user:password matching exactly what’s in relayhost (Postfix matches the entry by hostname first, so the brackets and port must agree). Then lock the file down and compile it to a hash database:

Terminal
sudo nano /etc/postfix/sasl_passwd
# Add: [host]:port user:password   (per provider, see below)

sudo chmod 0600 /etc/postfix/sasl_passwd
sudo chown root:root /etc/postfix/sasl_passwd
sudo postmap /etc/postfix/sasl_passwd
sudo chmod 0600 /etc/postfix/sasl_passwd.db

The postmap command creates /etc/postfix/sasl_passwd.db, the actual file Postfix reads at runtime. Rerun postmap any time you edit the plaintext file. Now jump to the section for your provider.

SendGrid 

SendGrid uses a single SMTP hostname (smtp.sendgrid.net) regardless of region. Use port 587 with STARTTLS, or port 465 with implicit SSL. Generate an API key first: in the SendGrid dashboard, go to Settings → API Keys → Create API Key, give it “Mail Send” permission, and copy the key (it starts with SG. and is only shown once).

The SendGrid quirk worth knowing, and worth quoting verbatim because it surprises people: per the SendGrid SMTP docs, “Set your username to the string apikey.” The literal six-letter string apikey is your SMTP username, not your account email. The API key itself goes in the password field.

In main.cf, set relayhost = [smtp.sendgrid.net]:587. In /etc/postfix/sasl_passwd:

/etc/postfix/sasl_passwd
[smtp.sendgrid.net]:587 apikey:SG.your_actual_api_key_here

Mailgun 

Mailgun’s SMTP server lives at smtp.mailgun.org. Per Mailgun’s documentation, “Mailgun SMTP servers listen on ports 25, 465, 587, and 2525“. Port 587 with STARTTLS is the recommended choice, and port 465 requires TLS. Add and verify your sending domain in the Mailgun dashboard first (Sending → Domains → Add New Domain), then go to that domain’s SMTP credentials section to grab the username and password Mailgun generates for you.

Mailgun’s quirk: the SMTP username looks like postmaster@your-mailgun-domain (typically [email protected] after you verify your custom domain). The password is a Mailgun-generated string, not your dashboard login password.

In main.cf, set relayhost = [smtp.mailgun.org]:587. In /etc/postfix/sasl_passwd:

/etc/postfix/sasl_passwd
[smtp.mailgun.org]:587 [email protected]:your_mailgun_smtp_password

Amazon SES 

Amazon SES uses regional SMTP endpoints. Examples include email-smtp.us-east-1.amazonaws.com, email-smtp.us-west-2.amazonaws.com, and email-smtp.eu-west-1.amazonaws.com. The full canonical list lives in the AWS General Reference under “Amazon Simple Email Service endpoints and quotas”. Use the region closest to your server.

SES makes TLS unconditional at the protocol level: “The Amazon SES SMTP endpoint requires that all connections be encrypted using Transport Layer Security (TLS).” SendGrid and Mailgun also support TLS but don’t enforce it server-side the same way; in this guide we enforce it client-side via the smtp_tls_security_level = encrypt setting in the shared block, so all three providers behave identically from your Postfix server’s perspective. SES supports two TLS modes: port 587 with STARTTLS, or port 465 with TLS Wrapper (also called implicit TLS).

SES has two gotchas. First: SMTP credentials must be generated through the SES console specifically (Amazon SES → SMTP settings → “Create SMTP credentials”). The SES console creates a backing IAM user with the right SES SMTP policy and returns an SMTP-formatted username + password, you cannot use a regular IAM access key directly as the SMTP password. Second: new SES accounts start in sandbox mode, which restricts sending to verified recipient addresses only. You’ll need to request production access through the SES console before you can send to arbitrary recipients.

In main.cf, set relayhost = [email-smtp.us-east-1.amazonaws.com]:587 (substitute your region). In /etc/postfix/sasl_passwd:

/etc/postfix/sasl_passwd
[email-smtp.us-east-1.amazonaws.com]:587 AKIA_YOUR_SMTP_USERNAME:your_ses_smtp_password

The SMTP username SES generates looks similar to an IAM access key ID (starts with AKIA) but it’s a separate credential generated by the SES console, not your regular IAM key.

Next steps 

After editing main.cf + sasl_passwd + running postmap, reload Postfix to apply the new configuration:

Terminal
sudo systemctl reload postfix

Send a test message using sendmail -t, which reads the From / To / Subject headers from the message body. Important: the From address MUST be a sender you have verified in your provider’s dashboard. SendGrid, Mailgun, and SES all reject messages from unverified senders.

Terminal
sendmail -t <<EOF
From: [email protected]
To: [email protected]
Subject: Postfix relay test

Body of the test message.
EOF

# Then watch the mail log:
sudo journalctl -u postfix -f

A successful delivery produces a line containing status=sent with the SMTP response from your provider. To debug failed sends, search the log for entries pertaining to your provider’s hostname or for any line containing status=bounced / status=deferred. Per-provider common errors:

  • SendGrid 401 Unauthorized: the SMTP username field has your account email instead of the literal string apikey. Fix the username, re-run postmap, reload Postfix.
  • Mailgun 535 authentication failed: the SMTP username is your dashboard login email instead of [email protected], or the domain isn’t verified yet.
  • SES “554 Message rejected: Email address is not verified”: your SES account is in sandbox mode. Verify the recipient (or request production access from the SES console).

If your messages reach Gmail or Microsoft inboxes but get bounced with a 5.7.26 authentication-checks error, the receiving end is rejecting your sending domain’s SPF or DKIM signature. See our companion guide on fixing the Gmail 550-5.7.26 bounce. If you’re configuring PHP applications on the same server to use this relay, follow up with our PHP mail() with Postfix guide. To inspect the local mail spool when debugging cron and root mail, see reading mail in Linux. For the wider Postfix maintenance picture, see our guide on automatic service restart with systemd, which applies the same approach to keeping the Postfix daemon up after a crash.

Support DevAnswers
Written, tested and maintained by one developer. Your support keeps these guides accurate and ad-light.
Buy me a coffee

25 replies

Leave a reply

  1. chandra

    [root@mailserver postfix]# cat /etc/ssl/certs/thawte_Primary_Root_CA.pem | sudo tee -a /etc/postfix/cacert.pem
    cat: /etc/ssl/certs/thawte_Primary_Root_CA.pem: No such file or directory

    1. Miah

      Was this issue resolved? I am facing the same problem.

  2. singleleagye

    Mar 25 12:47:27 ubuntu postfix/smtp[5794]: E0DADC51F5: to=, relay=none, delay=2.1, delays=0.01/0.01/2.1/0, dsn=4.4.1, status=deferred (connect to smtp.gmail.com[2404:6800:4003:c03::6c]:587: Network is unreachable)

  3. Tony Moey

    WOW, it works perfectly!
    Thanks heaps!

  4. Al Roberts

    Worked like a charm. Thank You!

  5. Haseeb

    [root@mantisbt ssl]# cat /etc/ssl/certs/thawte_Primary_Root_CA.pem | sudo tee -a /etc/postfix/cacert.pem
    cat: /etc/ssl/certs/thawte_Primary_Root_CA.pem: No such file or directory

    1. DevAnswers

      What is your distribution of Linux?

      Also see if you can locate the cert

      locate thawte_Primary_Root_CA.pem

      1. CMayo

        I have the same issue, i.e. 257 certs in /etc/ssl/certs but no thawte_Primary_Root_CA.pem:

        “cat: /etc/ssl/certs/thawte_Primary_Root_CA.pem: No such file or directory.”

        I’m on Raspbian Buster, deritive of Debian 10. Locate drew a blank on “thawte_Primary_Root_CA.pem” as did find.

        Can I substitute another cert?

          1. alexito_97

            thank you doctor.

  6. Robert Drummond

    Awesome! Thank you so much for this. I’ve been trying to find a simple solution to allow my home server to email me via SMTP and this worked on the initial try.

    1. DevAnswers

      Great! 🙂

  7. Thean Heng

    Cannot send email, the following error occur:
    (Host or domain name not found. Name service error for name=mail.khmerdeliveryservices.com
    type=AAAA: Host found)

    I did set up A record and AAAA record for mail.khmerdeliveryservices.com correctly from my domain registrar.

    1. DevAnswers

      What have you got for relayhost in /etc/postfix/main.cf?

      According to a DNS scan for you domain, you are using Namecheap for mail, is that right?

  8. Michael Japlin

    I’ve set this up with Mailgun so that WordPress comments will be emailed to my Gmail, however, I get this error in the log when I post a reply to someone.

    status=bounced (host smtp.mailgun.org[52.32.113.201] said: 550 5.1.0 Recipient rejected: <root@your_domain.co> (in reply to RCPT TO command))
    1. DevAnswers

      What is the email address in Mailgun? I assume it’s not root@your_domain.com and that’s why Mailgun is rejecting it. In that case, you will need to add a canonical map for postfix.

      For example, if your Mailgun email address is info@your_domain.com, your canonical map would be:

      root@your_domain.co info@your_domain.co

      Please see below comment on how to set up a canonical map.

  9. Ahmed

    The syslog shows this error when trying to send a test. Using mailgun.

    status=bounced (host smtp.mailgun.org[34.237.7.101] said: 550 5.7.1 Relaying denied (in reply to RCPT TO command)
  10. JJHef

    When I do a test email, nothing comes in. The syslog says this:

    postfix/smtp[19504]: 1EDFD41921: to=, relay=server81.web-hosting.com[192.64.118.70]:587, delay=1.9, delays=0.04/0.05/1.7/0.18, dsn=5.0.0, status=bounced (host server81.web-hosting.com[192.64.118.70] said: 550-Verification failed for 550-The mail server could not deliver mail to myname@linuxserver. The account or domain may not exist, they may be blacklisted, or missing the proper dns entries. 550 Sender verify failed (in reply to RCPT TO command))

    1. DevAnswers

      The problem is the from email address myname@linuxserver is invalid and the SMTP server is rejecting it.

      You will need to use a valid email address here, the same one you set up in sasl_passwd.

      To do this, we must do Postfix Address Rewriting.

      sudo nano /etc/postfix/main.cf

      Paste this to the bottom, save and exit.

      sender_canonical_maps = hash:/etc/postfix/canonical

      Edit this file

      sudo nano /etc/postfix/canonical

      Add in this file:

      myname@linuxserver [email protected]

      Where myname@linuxserver is what’s showing in the error log, and [email protected] is the email address of the account you’re trying to send email through.

      Save file and close.

      Now create the db file.

      sudo postmap hash:/etc/postfix/canonical

      Restart postfix service

      sudo service postfix restart

      Now try send another test email

      echo "Test Email message body" | mail -s "Email test subject" [email protected]
      1. JJHef

        This works, I can send that test message. But when I try to send via PHP, nothing is received. Here is a new error.

        postfix/qmgr[20768]: 8AF5C41923: from=, size=1252, nrcpt=1 (queue active)
        postfix/local[20955]: 8AF5C41923: to=, relay=local, delay=0.04, delays=0.03/0.01/0/0.01, dsn=5.1.1, status=bounced (unknown user: "webmaster")
          1. JJHef

            OK I did that, now I have a different error when trying to send PHP mail.

            status=bounced (host server81.web-hosting.com[192.64.118.70] said: 550-Verification failed for  550-No Such User Here" 550 Sender verify failed (in reply to RCPT TO command))
          2. DevAnswers

            This address: [email protected] is being rejected by the SMTP server because it doesn’t exist. Remember, this SMTP server will only except mail if the From email matches the account you are trying to send mail through.

            You will need to add another canonical map for [email protected].

            sudo nano /etc/postfix/canonical

            Add

            [email protected] [email protected]

            Where [email protected] is what’s showing in the error log, and [email protected] is the email address of the account you’re trying to send email through.

            Save file and close.

            Now create the db file.

            sudo postmap hash:/etc/postfix/canonical

            Restart postfix service

            sudo service postfix restart

            Now try send another test email

  11. JJHef

    My host Namecheap says to use mail server server81.web-hosting.com and port 465, will this work?

    1. DevAnswers

      There’s no reason to use port 465. That mail server servers responds to port 587 so I recommend using that.