How to Test Your SMTP Configuration (Without Risking Real Email)
What "SMTP testing" actually means
"SMTP testing" gets used for at least three different things, and mixing them up is how teams end up with a config that "works" in a demo and then silently fails in production. There's testing that your SMTP credentials and connection settings are correct (auth, port, TLS). There's testing that your app actually calls the mailer correctly for every code path that's supposed to send (not just the one you clicked through manually). And there's testing what the resulting email looks like once it lands in an inbox, headers, rendering, spam flags included. A tool that only covers the first one will still let broken invite emails or malformed password resets ship.
Set up a sink that behaves like production, minus the risk
Before you touch real SMTP credentials, point your app at an address that only you can see. In Inceptmail that's one private inbox per project (e.g. a prefix like [email protected]), so every message your config sends during testing lands somewhere real, visible in a few seconds, and never anywhere near an actual user. That matters because a lot of SMTP bugs only show up once a message has actually been accepted and delivered, not when your library returns a 250 OK. Pointing at a throwaway address or a catch-all you don't monitor just hides the failure instead of catching it.
The checklist: what to actually verify
- Authentication: does the connection actually succeed with the real username, password, and port, not just a cached success from last week
- Encryption: TLS/STARTTLS is actually negotiated on the port you think it is, not silently downgraded to plaintext
- From and Reply-To: the sender address matches what you configured, and isn't accidentally falling back to a default from the mail library
- Headers: Message-ID, Date, and any custom headers your app sets are actually present, not stripped by a proxy or relay in between
- Attachments: files survive the trip with the right MIME type and aren't corrupted or dropped by the relay
- Timing: how long delivery actually takes under load, not just for the first test message you send by hand
Common mistakes that still pass "it sent"
- It works from your laptop, but not from the CI runner: the pipeline's egress IP is on a provider block list, or outbound port 587/465 is firewalled, something your laptop's network never hits
- The SDK swallows the send error: your mailer call is wrapped in a try/catch that logs and moves on, so a 550 rejection never surfaces anywhere a human looks
- Staging shares credentials with production: a config bug in staging quietly sends to real customers instead of failing loudly, because both environments point at the same sending domain
- Nobody re-checks it after a dependency bump: the mail library's major version changes a default (e.g. how it handles the envelope sender) and nothing in the test suite would ever catch it
Automate it, so nobody has to remember to re-check
A manual check catches the config the day you write it, and nothing after that. The useful version runs as part of CI: send a real message through the config you're about to ship, fetch it back over an API a few seconds later, and assert on what actually arrived, the headers, the from address, the attachment, the content. That's the same shape as checking any other integration, the only thing that's different about email is needing somewhere real to receive it that isn't a developer's personal inbox. Once that loop exists, a broken SMTP config fails a pull request instead of a signup.