Skip to content
Skip to main content

Send email from Docker without SMTP

Last updated:

You package an app into a Docker image, ship it to a cluster, and the first time it tries to send a notification the connection to your SMTP server hangs and times out. The container can’t reach port 25, 465, or 587, and adding postfix to the image just moves the failure inside the container. Most managed hosts, including AWS, GCP, and Azure, block outbound SMTP by default to cut spam, so the mail server you tested locally is unreachable in production.

This guide skips SMTP entirely. You send email from inside a container through one HTTPS POST to a REST endpoint, with the API key passed as an environment variable. No mail transfer agent, no port 25, no local relay to babysit.

How do I send email from a Docker container without SMTP?

Section titled “How do I send email from a Docker container without SMTP?”

Send a single HTTPS POST to POST /v3/grants/{grant_id}/messages/send over port 443, which every container can reach. You pass the recipient, subject, and body as JSON, and the API delivers the message through the connected account’s provider. Because it rides on HTTPS, the SMTP ports your host blocks never enter the picture.

The request below sends a plain notification email. It targets the send endpoint, which works the same across Gmail, Microsoft 365, Yahoo, iCloud, and IMAP, so one container image reaches every provider your users connect. For a grant-based send, to is the only recipient field you must set; the sender defaults to the connected account, and subject and body are optional but you’ll almost always set them.

A successful call returns 200 with the sent message object, including its grant_id and id. If you set send_at for scheduled delivery, the API returns 202 instead, since the message is queued rather than sent immediately.

How do I send email from a terminal without setting up postfix or sendmail?

Section titled “How do I send email from a terminal without setting up postfix or sendmail?”

Run the same curl from any shell. The send endpoint replaces the local mail transfer agent, so you don’t install postfix or sendmail, configure a relay host, or maintain /etc/aliases. A bare alpine image with curl added weighs roughly 8 MB, versus the extra packages postfix drags in, and that smaller surface removes a whole class of mail-config bugs.

This pattern fits cron jobs, CI steps, and one-off scripts the same way it fits a long-running service. The endpoint accepts HTML in the body field, so terminal scripts can send formatted reports, not just plain text. The example below sends an HTML body, useful when a nightly job emails a summary table or a styled status block.

For a fuller terminal walkthrough including scheduling, see send email from a Bash script or cron job.

What can I use instead of Send-MailMessage in PowerShell?

Section titled “What can I use instead of Send-MailMessage in PowerShell?”

Use Invoke-RestMethod against the send endpoint. Microsoft marked Send-MailMessage obsolete, and its docs warn the cmdlet “can’t guarantee secure connections to SMTP servers.” A REST call sidesteps SMTP completely, which matters in a Windows container where no SMTP relay exists. You build a hashtable, convert it to JSON, and POST it.

The script below reads the API key from an environment variable, so the secret never sits in source. It sends one message and works identically on Windows, Linux, and macOS containers. The to field takes an array of address objects, mirroring the JSON shape the API expects, and you can add cc or bcc arrays the same way.

Microsoft documents the obsolete status in the Send-MailMessage reference and points to Send-MgUserMail (the Microsoft Graph PowerShell SDK) and MailKit as replacements. A REST send is a provider-agnostic option that avoids SMTP entirely, which is what a container without a relay needs.

SMTP relay vs the Email API in a container

Section titled “SMTP relay vs the Email API in a container”

An SMTP relay needs an open outbound port, a mail library or local agent, and connection retries when the relay is slow. The REST approach needs only an HTTPS client, which every base image already has through curl. The table compares both on the work a containerized send actually requires. The unified column is the path this guide uses.

TaskSMTP relay in a containerNylas Email API
Outbound port25, 465, or 587, often blocked443, always open
In-image dependencypostfix, sendmail, or an SMTP librarycurl only
AuthRelay username and passwordAuthorization: Bearer API key
Delivery feedbackParse SMTP response codes200/202 plus webhooks
Provider reachOne relay endpointGmail, Microsoft 365, Yahoo, iCloud, IMAP

Be honest about the tradeoff: if you already run a trusted internal relay that your container can reach on a private network, and you only send to one domain, SMTP is simpler and has no per-message cost. The REST path wins when the network blocks SMTP, when you send across providers, or when you want delivery webhooks instead of parsing response codes.

How do I keep the API key out of the image?

Section titled “How do I keep the API key out of the image?”

Pass the key as an environment variable at runtime, never baked into a layer. A secret written with ENV or copied into the image stays in the image history across all of its layers, and docker history reveals it to anyone who pulls the image. Inject it with docker run -e, a Compose environment block, or a Kubernetes Secret, so the value lives only in the running container.

The send endpoint reads Authorization: Bearer <NYLAS_API_KEY>, and the scripts above pull that from $NYLAS_API_KEY. At runtime you supply it like docker run -e NYLAS_API_KEY=... your-image. In Kubernetes, mount a Secret through envFrom so the key never appears in the manifest or in docker inspect. Rotating the key then means updating one secret, not rebuilding and redeploying the image.

For the wider problem of hosts that drop SMTP traffic, see why SMTP ports are blocked and how to work around it and the send email without SMTP overview.