# 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.

Source: https://vpsnine.com/tutorials/send-email-from-vps-smtp-relay · Updated: 2026-10-21

Difficulty: intermediate · Time: about 20 minutes · Tested on: Debian 13 Stable

Prerequisites:

- 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

```bash
sudo apt update
sudo apt install -y postfix libsasl2-modules mailutils
```

The installer asks a few questions:

1. **General type of mail configuration:** choose **Satellite system**.
2. **System mail name:** your server's full name or your domain, for example `web-1.example.com`. It's stored in `/etc/mailname` and used for mail from local users like `root`.
3. 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:

```bash
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:

```bash
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_passwd
```

The host and port must match `relayhost` exactly, brackets included. Run `postmap` again whenever you change the file.

Check the configuration and restart:

```bash
sudo postfix check
sudo systemctl restart postfix
```

`postfix check` prints nothing when all is well.

## Send a test message

```bash
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:

```bash
sudo journalctl -t postfix/smtp -n 20
```

A 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:

```bash
mailq
```

## Use it from your apps

- **Anything that calls `sendmail`** (cron's output, `mail`, PHP's `mail()`, Netdata alerts, `unattended-upgrades` reports) now goes through the relay with no further setup.
- **Apps with their own SMTP settings** can use `localhost`, port `25`, 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:

```bash
echo 'root: you@example.net' | sudo tee -a /etc/aliases
sudo newaliases
```

## Troubleshooting

**`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](https://vpsnine.com/tutorials/point-a-domain-to-your-vps).
- Have Netdata email its alerts: [monitor with Netdata](https://vpsnine.com/tutorials/install-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](https://vpsnine.com/help/open-port-25) and set [reverse DNS](https://vpsnine.com/help/reverse-dns) before you ask us to open it. Runs on [Debian 13](https://vpsnine.com/os/debian-13) and every other image, on all [plans](https://vpsnine.com/plans).
