SMTP, the Simple Mail Transfer Protocol, is the standard for sending email. A mail app or a script uses it to hand a message to its provider, which uses it to pass the message on to the recipient's server. It only sends: reading a mailbox is a separate job, done with IMAP, POP3 or JMAP.
RFC 5321 defines the protocol, first published as RFC 821 in August 1982, and RFC 5322 the messages it carries. Revisions of both, approved as full Internet Standards, are waiting in the RFC Editor's queue. Apps may reach their own provider in other ways, but between providers, mail still travels over SMTP.
How SMTP works: one message from app to inbox
Take Ada at example.org writing to Grace at example.com, with each program named as in RFC 5598:
- Ada's app writes the message. It is the mail user agent (MUA): an email client, or the mail library in your code.
- Her provider's server accepts it. The mail submission agent (MSA), on port 587 or 465, asks her to sign in and, as RFC 6409 allows, fixes details such as a missing Date header.
- A transfer agent finds Grace's server. The mail transfer agent (MTA) looks up the MX records of
example.comand tries the lowest-numbered one first. A domain with no MX record is its own mail server. - The two servers talk SMTP on port 25. Where both support it, they switch to TLS first. The receiving MTA checks who is sending, then accepts or refuses the message.
- The message reaches the mailbox. A mail delivery agent (MDA) files it where Grace's app can read it.
Step 3 is an ordinary DNS query:
$ dig +short MX example.com10 mx1.example.com.20 mx2.example.com.Each server on the way adds a Received: line, so the headers trace a message's path. The email address checker reads the MX records behind an address, so you can see whether its domain takes mail before you write to it.
What is an SMTP server?
Any program that takes mail over SMTP, in one of two jobs. The outgoing server in a mail app's settings is a submission server: it takes mail only from its own users, once they sign in. The servers in a domain's MX records take mail for that domain from anyone, without a sign-in.
A server that passes mail on rather than delivering it is a relay, and an SMTP relay service is a sending service's submission server.
SMTP commands: one conversation, line by line
This is Ada's app submitting her message on port 587. C: is the client and S: the server.
S: 220 smtp.example.org ESMTP readyC: EHLO laptop.example.orgS: 250-smtp.example.orgS: 250-SIZE 26214400S: 250-STARTTLSS: 250 ENHANCEDSTATUSCODESC: STARTTLSS: 220 2.0.0 Ready to start TLS (TLS handshake: everything below is encrypted)C: EHLO laptop.example.orgS: 250-smtp.example.orgS: 250-SIZE 26214400S: 250-AUTH PLAIN LOGINS: 250 ENHANCEDSTATUSCODESC: AUTH PLAIN AGFkYUBleGFtcGxlLm9yZwBhcHAtcGFzc3dvcmQ=S: 235 2.7.0 Authentication successfulC: MAIL FROM:<[email protected]>S: 250 2.1.0 OKC: RCPT TO:<[email protected]>S: 250 2.1.5 OKC: DATAS: 354 Start mail input; end with <CRLF>.<CRLF>C: From: Ada <[email protected]>C: To: Grace <[email protected]>C: Subject: Lunch on Friday?C: Date: Fri, 30 Oct 2026 09:12:00 +0000C: Message-ID: <[email protected]>C:C: Are you free at one?C: .S: 250 2.0.0 OK queued as 4F2A91C: QUITS: 221 2.0.0 ByeEHLOasks what the server supports, one extension per250-line, until a line with a space after the code. It replacedHELO, and SMTP with extensions is often called ESMTP.STARTTLSswitches to TLS. RFC 3207 then has both sides forget everything said before, so the client sendsEHLOagain, and this server offersAUTHonly now.AUTH PLAINsigns in, once the connection is encrypted.MAIL FROMandRCPT TOare the envelope: the return address, then one command per recipient.DATAcarries the message: header fields, a blank line, the body and a line holding only a dot. A leading dot in the message is doubled in transit, so the end cannot come early.250after the dot means the server now owns the message, and any later failure is its to report.
Between servers on port 25 the conversation is the same, minus AUTH. To try one yourself, use OpenSSL, which sends the first EHLO and STARTTLS for you:
openssl s_client -connect smtp.example.org:587 -starttls smtp -crlf -quietSMTP reply codes and enhanced status codes
The first digit of every reply says what to do next: 2 means done, 3 means go on, 4 means a temporary failure worth retrying, and 5 means a permanent one.
A server that announces ENHANCEDSTATUSCODES, as the one above does, adds a code from RFC 3463 such as 5.1.1: the class again, the area (1 is the address, 2 the mailbox, 3 the mail system, 4 the network, 5 the protocol, 6 the content and 7 security or policy), then a detail. The replies people meet most:
| Reply | Meaning | Next step |
|---|---|---|
250 2.0.0 | Accepted | None: the receiver is now responsible |
421 4.7.0 | Not now, closing the connection | Retry later |
452 4.2.2 | The mailbox is full | Retry, then give up if it stays full |
530 5.7.0 | Start TLS or sign in first | Turn on TLS and authentication |
535 5.7.8 | Wrong username or password | Fix the credentials |
550 5.1.1 | No such mailbox | Stop mailing the address |
550 5.7.1 | Refused by the receiver's policy | Read the reply text for the reason |
550 5.7.26 | More than one authentication check failed | Fix SPF, DKIM and DMARC |
552 5.3.4 | The message is too big | Send it smaller |
The SMTP envelope and the message headers
The envelope is what MAIL FROM and RCPT TO say during the conversation. The headers are part of the content sent after DATA. RFC 5321 defines one, RFC 5322 the other, and nothing makes them match.
| Envelope | Headers | |
|---|---|---|
| Sender | MAIL FROM, the return address for bounces | From:, the author people see |
| Recipients | One RCPT TO per delivery | To: and Cc: |
| After delivery | Kept as a Return-Path: header | Kept as written |
That gap is how Bcc works, since a blind copy gets a RCPT TO but stays out of the headers others see. It is also how a sending service can use its own bounce address while yours stays in From.
SPF checks the envelope, the domain in MAIL FROM, not the From line people read. That is why DMARC counts an SPF pass only when that domain aligns with From. What is SPF? explains the check, and What is DMARC? explains alignment.
Which SMTP port should you use: 25, 587 or 465?
SMTP uses port 25 between servers, and 587 or 465 when an app or your code sends through a provider.
| Port | Used for | Encryption |
|---|---|---|
| 25 | Server to server, delivering to a domain's MX hosts | STARTTLS, where both sides support it |
| 587 | Submission: apps and code sending through their provider, after a sign-in | STARTTLS |
| 465 | Submission, as on 587 | TLS from the first byte, called implicit TLS |
RFC 8314 has recommended implicit TLS on 465 since 2018, while asking clients and servers to support both ports during a transition of several years. On 587, make the client require STARTTLS: an attacker who can alter traffic can delete the offer, and a client that does not insist carries on in plain text.
Older guides call 465 deprecated, but RFC 8314 gave it to submission after a brief, withdrawn registration for SMTP over TLS. Port 2525, which some guides suggest, has no standard behind it: IANA's registry gives it to an unrelated service.
Why is port 25 blocked?
Because computers taken over by malware send spam straight to receiving servers. M3AAWG, the industry's anti-abuse working group, has recommended since 2005 (updated in August 2023) that networks block port 25 except for mail servers they allow, and offer authenticated submission on 465 and 587.
Google Cloud blocks port 25 to destinations outside your network but not 587 or 465, and Amazon EC2 blocks it to public addresses until you ask for that to be lifted. So code at home or in the cloud sends through a provider, which handles port 25.
Is SMTP secure?
Not by design. RFC 5321 calls SMTP mail "inherently insecure", because anyone can connect to a server and claim any sender. Two layers were added later: TLS for the connection, and SPF, DKIM and DMARC for the sender's identity.
Between servers, encryption is opportunistic: the receiver offers STARTTLS and the sender upgrades if it can. RFC 3207 forbids a public server from requiring it for local delivery, so mail from a server without TLS still arrives, and an attacker on the path can strip the offer unnoticed.
MTA-STS and TLS reporting
MTA-STS (RFC 8461) lets a receiving domain publish a rule: use TLS with a valid certificate, and deliver only to these MX hosts. It takes a TXT record and a policy file served over HTTPS:
_mta-sts.example.com. TXT "v=STSv1; id=20261031"https://mta-sts.example.com/.well-known/mta-sts.txt version: STSv1mode: enforcemx: mx1.example.commx: mx2.example.commax_age: 604800In enforce mode, a sender will not deliver to a host that fails the check. testing mode delivers anyway and reports failures, the safe way to start. Reports go to the address in a TLS reporting record (RFC 8460), such as v=TLSRPTv1; rua=mailto:[email protected] at _smtp._tls.example.com, once a day, in JSON.
DANE
DANE does the same through DNS: TLSA records for each MX host, at names such as _25._tcp.mx1.example.com, which count only in a zone signed with DNSSEC.
All of this protects one hop at a time. As RFC 3207 puts it, SMTP is not an end-to-end mechanism, so every server that relays a message can read it.
SMTP authentication (SMTP AUTH)
A submission server relays only for people who sign in: RFC 6409 has it refuse MAIL FROM until the session is authenticated, and the AUTH command from RFC 4954 carries the credentials.
PLAIN, what mail apps call "Normal password", sends the username and password as base64 that anyone can decode, so RFC 4954 requires servers to have a setting that refuses plain-text passwords without encryption. OAUTHBEARER, from RFC 7628, sends an OAuth token instead.
Bounces and deferrals: what happens when delivery fails
A 4xx reply defers the message. The sender keeps it queued and tries again: RFC 5321 asks for at least 30 minutes between attempts and at least four to five days before giving up. Some receivers answer 4xx on purpose to a sender they have not seen before, a practice called greylisting, because real servers retry and most spam software does not.
A 5xx reply is final, and so is a deferral that runs out of time. The sending server then mails a bounce, a non-delivery report, to the envelope sender, with an empty envelope sender of its own (MAIL FROM:<>) so a bounce that fails has no address to come back to.
Many bounces can be avoided: the email address checker catches bad syntax, domains that take no mail and throwaway addresses before the first send.
SMTP or an email API?
Code can hand mail to a sending service over SMTP, or with an HTTPS request to its API.
| SMTP | Email API | |
|---|---|---|
| Works with | Any software that sends mail, unchanged | Code written for that service |
| Per message | Several commands and replies | One HTTPS request |
| Changing provider | New host and password | New code |
| Errors | Reply code, enhanced code and text | HTTP status and JSON |
| Tags or a send time | Custom headers, where supported | Fields in the request |
Neither success means delivered: both mean queued, and the outcome arrives later as bounces, events or webhooks. SMTP suits software you do not want to change, such as a CMS or a printer. An API suits code you write yourself, where one request carries everything.
What Gmail, Yahoo and Microsoft require of senders
The largest mailbox providers add rules of their own:
- Gmail asks every sender for SPF or DKIM, a TLS connection, valid forward and reverse DNS and messages formatted by RFC 5322, and senders of more than 5,000 messages a day to Gmail accounts for SPF, DKIM and DMARC.
- Yahoo asks every sender for valid forward and reverse DNS and compliance with RFCs 5321 and 5322, and bulk senders for SPF, DKIM and DMARC.
- Outlook.com refuses mail from senders of 5,000 or more messages whose SPF, DKIM and DMARC fall short, with
550 5.7.515.
Valid reverse DNS means a PTR record names a host that resolves back to the sending IP. Our posts on SPF, DKIM and DMARC cover the details, and the deliverability checker reads a domain's SPF, DKIM, DMARC, BIMI and MX records from live DNS.
Where Nextmail fits
Nextmail runs the submission side for you. Any software that speaks SMTP, from a framework's mailer to a printer, can send through smtp.nextmail.sh on 465 with TLS from the first byte or 587 with STARTTLS, signed in as nextmail with an API key that has the emails:send scope. Nothing is accepted before the connection is encrypted.
Each message is the same send as POST /emails with that key, held to the key's scopes, the workspace's quota and its suppression list. The 250 2.0.0 OK queued as reply carries the id that GET /emails/{id} reads, and the same Message-ID handed over again for the same recipients sends nothing new, so a mailer that retries cannot send twice. Send over SMTP has the settings and every reply.
Mail apps, which read as well as send, sign in to the same server with the whole address and an app password made for it. What they send passes the same checks and limits as the web app, picks up the address's signature and leaves a copy in Sent. Mail apps has the settings for each app.
Free tools
Try what you just read on your own setup. They are free and need no account.
References
- 1RFC 5321: Simple Mail Transfer ProtocolIETF
- 2RFC 5322: Internet Message FormatIETF
- 3RFC 3463: Enhanced Mail System Status CodesIETF
- 4RFC 4954: SMTP Service Extension for AuthenticationIETF
- 5RFC 6409: Message Submission for MailIETF
- 6RFC 8314: Cleartext Considered Obsolete: Use of Transport Layer Security (TLS) for Email Submission and AccessIETF
- 7RFC 8461: SMTP MTA Strict Transport Security (MTA-STS)IETF
- 8RFC 8460: SMTP TLS ReportingIETF
- 9M3AAWG Best Common Practices for Managing Port 25 for IP NetworksM3AAWG
- 10Email sender guidelinesGoogle
Google Workspace