Markdown

Send email from Hetzner Cloud

Hetzner blocks outbound ports 25 and 465 on cloud servers by default. A mail library that connects to an SMTP server on either port fails with Connection timeout or ETIMEDOUT, even when the host, username and password are right. Hetzner lifts the block on request once your account is a month old and has paid its first invoice, case by case.

Updated Nov 14, 20262 min read

Port 587 and HTTPS aren't blocked, so an app on Hetzner Cloud can send through Groundmail from day one, with no request to Hetzner:

Your app Use Code change
You control the code The Groundmail API or an SDK, over HTTPS Replace the send call
It only speaks SMTP (Ghost, n8n, WordPress, a framework's mailer) The SMTP relay on port 587 None: change the SMTP settings

Prerequisites

  • A Groundmail account with a verified sending domain. A subdomain such as mail.yourdomain.com works well.
  • An API key (gm_…) from API keys in the dashboard.

Send with the API

Give your app the key as the GROUNDMAIL_API_KEY environment variable, the same way it gets its other secrets: an .env file, a systemd unit, or your container's environment. Then send with an SDK.

Node.js

Terminal
npm install groundmail
JavaScript
import { Groundmail } from 'groundmail'

const groundmail = new Groundmail(process.env.GROUNDMAIL_API_KEY)

await groundmail.emails.send({
  from: 'App <no-reply@mail.yourdomain.com>',
  to: 'user@example.com',
  subject: 'Reset your password',
  html: '<p>Click the link to reset your password.</p>',
})

Already on Nodemailer? Swap the SMTP transport for the Nodemailer transport, which sends over HTTPS, and keep your sendMail calls.

Python

Terminal
pip install groundmail
Python
import os
from groundmail import Groundmail

groundmail = Groundmail(os.environ["GROUNDMAIL_API_KEY"])
groundmail.emails.send(
    from_="App <no-reply@mail.yourdomain.com>",
    to="user@example.com",
    subject="Reset your password",
    html="<p>Click the link to reset your password.</p>",
)

Go, PHP and Ruby have SDKs too: see SDKs. Any other language can call POST https://api.groundmail.dev/emails with the key: see the API reference.


Keep SMTP

If your app can only send over SMTP, point it at Groundmail's relay on port 587:

Setting Value
Host smtp.groundmail.dev
Port 587
Encryption STARTTLS
Username groundmail
Password An SMTP credential from SMTP in the dashboard

If your app is set to port 465 (implicit TLS), change it to 587 with STARTTLS. See SMTP.

Running your apps with Coolify on a Hetzner server? See Send email from Coolify for where these settings go.


Troubleshooting

What you see What to do
Connection timeout or ETIMEDOUT when sending Your app is connecting on port 25 or 465. Change the port to 587 with STARTTLS, or switch to the API.
535 from the SMTP relay The username isn't groundmail, or the password isn't an SMTP credential. Create one under SMTP.
550 saying the domain isn't verified The From address isn't on a verified domain. See Domains.

Was this page helpful?