Documentation

Sending email from your app

Why your app cannot send email until you give it a mail provider, and how to set one up.

Your app cannot send email on its own

Several of the apps we install can send email — Ghost sends newsletters and sign-in codes, WordPress sends password resets, Nextcloud and Gitea send notifications. None of them can do it out of the box on your server. You have to give them an outbound mail provider first.

This is deliberate, and it is worth understanding why, because the alternative is worse for you than it looks.

Why we block the direct route

Left alone, most of these apps try to deliver mail themselves, by connecting straight to the recipient's mail server on port 25. It works right up until it doesn't. Mail sent that way carries none of the signatures that modern mail systems check for, so Gmail, Outlook and corporate mail servers treat it as suspicious and put it in spam — or drop it silently and tell nobody.

Worse, that mail goes out under an address shared with other customers. One server sending questionable mail gets that address a bad reputation, and then everybody's mail starts landing in spam. So we block port 25 outbound on every server.

The authenticated ports mail providers actually use — 465 and 587 — are open and always have been. Those need a username and a password, which is exactly what makes them trustworthy to the receiving end.

If your app looks like it is sending mail but nothing ever arrives, this is almost always why. Set up a provider below rather than looking for a fault in the app.

What you need

An account with an email sending service. Resend, Mailgun, Postmark, Brevo and SendGrid all work and all have a free tier that is enough for a small site. You can also use a mailbox you already pay for, such as Google Workspace or Microsoft 365, though those limit how much you can send.

Whichever you choose, you will finish setup holding four things: a host name, a port, a username and a password. You will also be asked to verify the domain you want to send from, by adding DNS records the provider gives you. Do that part properly — it is what stops your mail being treated as forged.

Setting it up on Ghost

Ghost is the one people get stuck on, because its mail settings are not in the admin area. Looking under Settings for them is a dead end — they live in the server's configuration file, so you set them over SSH.

Connect to your server, then open the file that describes how Ghost runs:

$ sudo nano /opt/ghost/docker-compose.yml

Find the block that begins with 'environment:' underneath 'ghost:'. It already has several lines starting with 'database__'. Add these below them, lined up in the same column, replacing the host, username, password and address with the ones your provider gave you:

mail__transport: SMTP
mail__options__host: smtp.resend.com
mail__options__port: "465"
mail__options__secure: "true"
mail__options__auth__user: resend
mail__options__auth__pass: "your-api-key-here"
mail__from: "Your Name <hello@yourdomain.com>"

Indentation matters in this file. Every line you add must start in the same column as the 'database__' lines above it — spaces, never tabs. If Ghost refuses to start afterwards, that is the first thing to check.

Save the file and close the editor, then apply it:

$ cd /opt/ghost && docker compose up -d

Ghost restarts with the new settings. Your posts, members and settings are untouched — they live outside the container, so restarting it this way is safe and takes a few seconds.

To check it worked, go to Settings, then Email newsletter, and send yourself a test. If it arrives, you are done.

Some providers use port 587 instead of 465. If yours does, set the port to "587" and secure to "false" — that combination is still encrypted, it just starts the encryption a moment later.

Signing in to Ghost does not need email

Ghost normally emails you a six-digit code every time you sign in from a new device. On a server with no mail provider that code can never arrive, which would lock you out of your own site — so we turn that feature off before you ever see it. You sign in with your email address and your password, and that is all.

Once you have mail working you can switch the codes back on if you want them. Do it in that order, though, and make sure a test message actually reaches you first. Turning them on while mail is broken is the one change that can shut you out.

The other apps

The same four details work everywhere, but each app asks for them in its own place. WordPress needs a plugin — WP Mail SMTP is the usual one — because it has no built-in setting for this. Nextcloud has a form under Administration settings, then Basic settings. Gitea keeps its mail configuration in /opt/gitea, in the same style as Ghost.

In every case, use the authenticated details from your provider. Any option offering to send mail directly, or to use the local sendmail program, will not work here.

Keeping the password safe

The password you paste into that file is stored on your server in plain text, in the same file as your database password. That is normal for this kind of configuration, and the file is only readable by the administrator account.

Most providers issue an API key rather than your real account password, and let you revoke a single key without touching anything else. Use that if it is offered. If you ever share a copy of the file — in a support ticket, for instance — take the key out first.

Keep reading