SMTP Test: Send a Test Email and Inspect It

Send a test email through send.smtp.dev with swaks, curl, openssl, or your app's mailer, then read it back over IMAP, POP3, or the REST API.

Send a message through the sandbox's SMTP server, then open what arrived: headers, MIME parts, raw source. send.smtp.dev only delivers to accounts in your sandbox, so a test email can't reach a real recipient.

Settings

SettingValue
Hostsend.smtp.dev
Port587, STARTTLS
UsernameThe account's full address
PasswordThe account's password
SizeUp to 20 MB per message

Create two accounts on the Accounts page: one to send from, one to receive. The examples use sender@test.example.com and qa@test.example.com, and read the sender's password from SMTP_PASSWORD.

The recipient has to be an account in your sandbox. Any other address is refused.

From the Command Line

swaks

swaks is the usual SMTP test tool: brew install swaks or apt install swaks. It prints the whole SMTP conversation, so a refused login or recipient shows the server's exact reply.

swaks --server send.smtp.dev --port 587 --tls \
  --auth-user sender@test.example.com --auth-password "$SMTP_PASSWORD" \
  --from sender@test.example.com --to qa@test.example.com \
  --header "Subject: SMTP test" --body "Sent with swaks"

curl

curl speaks SMTP, so there's nothing to install. Write the message to message.txt:

From: sender@test.example.com
To: qa@test.example.com
Subject: SMTP test

Sent with curl.

Then send it:

curl smtp://send.smtp.dev:587 --ssl-reqd \
  --user "sender@test.example.com:$SMTP_PASSWORD" \
  --mail-from sender@test.example.com \
  --mail-rcpt qa@test.example.com \
  --upload-file message.txt

Add -v to see each command and reply.

By Hand with openssl

Typing the SMTP commands yourself shows exactly where a conversation fails. Port 587 starts TLS before login, which telnet can't do, so connect with openssl:

openssl s_client -starttls smtp -connect send.smtp.dev:587 -crlf -quiet

-crlf sends the line endings SMTP expects. -quiet also stops openssl from reading a line that starts with R as a renegotiation command, which would otherwise swallow RCPT TO.

Build the login token in another terminal:

printf '\0%s\0%s' 'sender@test.example.com' "$SMTP_PASSWORD" | base64

Then type one line at a time and wait for each reply:

EHLO localhost
AUTH PLAIN <token>
MAIL FROM:<sender@test.example.com>
RCPT TO:<qa@test.example.com>
DATA
From: sender@test.example.com
To: qa@test.example.com
Subject: SMTP test

Typed by hand.
.
QUIT

The EHLO reply lists what the server supports, including SIZE, its message size limit in bytes. The line with a single . ends the message.

ReplyMeaning
220Ready
250Accepted
235Logged in
354Send the message, end it with a line holding only .
530Log in first
535Login failed
550Refused, usually the recipient
552Over the size limit

From Your App

Point the app's mailer at the sandbox. Sending from code:

import nodemailer from 'nodemailer'

const transport = nodemailer.createTransport({
  host: 'send.smtp.dev',
  port: 587,
  requireTLS: true,
  auth: {
    user: 'sender@test.example.com',
    pass: process.env.SMTP_PASSWORD,
  },
})

await transport.sendMail({
  from: 'sender@test.example.com',
  to: 'qa@test.example.com',
  subject: 'SMTP test',
  text: 'Sent with Nodemailer',
})

Or in your framework's mail settings:

MAIL_MAILER=smtp
MAIL_HOST=send.smtp.dev
MAIL_PORT=587
MAIL_USERNAME=sender@test.example.com
MAIL_PASSWORD=your-account-password
MAIL_FROM_ADDRESS=sender@test.example.com

Some frameworks can send a test email for you. Django has python manage.py sendtestemail qa@test.example.com. In Laravel, run php artisan tinker, then Mail::raw('Sent with Laravel', fn ($message) => $message->to('qa@test.example.com')->subject('SMTP test'));.

Test runners often replace the mailer. Django's test runner switches to an in-memory backend, and Rails sets delivery_method = :test in the test environment. Mail sent from those tests never reaches SMTP, so set the SMTP settings on the server your end-to-end tests run against.

Read It Back

Open the recipient account in Mail, or log in to webmail.smtp.dev with the account's address and password.

To script it, use the REST API. List the inbox, newest first, then fetch a message by id:

curl "https://api.smtp.dev/accounts/{accountId}/mailboxes/{mailboxId}/messages" \
  -H "X-API-KEY: $SMTP_DEV_API_KEY"

curl "https://api.smtp.dev/accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}/source" \
  -H "X-API-KEY: $SMTP_DEV_API_KEY"

The /source endpoint returns the message exactly as it arrived. The API quickstart covers finding the account and mailbox ids.

curl reads mail over IMAP and POP3 too, with the recipient's own credentials:

# UIDs of the messages in the inbox
curl "imaps://imap.smtp.dev/INBOX" --request "UID SEARCH ALL" \
  --user "qa@test.example.com:$QA_PASSWORD"

# one message, raw
curl "imaps://imap.smtp.dev/INBOX;UID=1" --user "qa@test.example.com:$QA_PASSWORD"

# the first message over POP3
curl "pop3s://pop.smtp.dev/1" --user "qa@test.example.com:$QA_PASSWORD"

What to Check

  • Headers. From, Reply-To, Date, and Message-ID are present and say what you intended.
  • Both parts. A multipart message has a plain text and an HTML part. Read both. The plain text part is often the one nobody looked at.
  • Links. They point at the right environment, with absolute URLs. A localhost link in a staging email is a common bug.
  • Attachments. Filename, content type, and size match what the app attached. Size limits covers how encoding grows them.
  • Encoding. Non-ASCII names and subjects arrive intact.

When It Fails

SymptomCause
535 after AUTHWrong password, or the username isn't the full address
Recipient refusedThe address isn't an account in your sandbox
552The encoded message is over 20 MB
Connection times outThe network blocks outbound SMTP. Some networks block port 587, most cloud providers block 25
TLS error right after connectingThe client expects implicit TLS (port 465 settings). Use STARTTLS on 587

Testing Your Own Server

swaks, curl, and openssl work against any SMTP server: change the host, port, and credentials. The sandbox is useful as the far end. Send through your own server or provider to an address on a domain whose MX points at mx.smtp.dev, and the message arrives with SPF, DKIM, and DMARC results next to the raw source.