Mautic email deliverability: replace SMTP with the Symfony Mailer DSN transport
Mautic 5 runs on Symfony Mailer, not SwiftMailer — which means it can take a native mailkite+api:// DSN instead of generic SMTP. This tutorial covers the install, the DSN config, and why campaign-send errors are more useful than an SMTP rejection code.
Mautic is a marketing-automation platform, so email is the product, not a side effect. A contact form on a CMS sends a handful of messages a day; a Mautic campaign to a real segment can fan out to thousands in one send. That makes Mautic’s mail transport the single highest-leverage setting in the whole install — and most Mautic docs still point you at generic SMTP.
Mautic 5 doesn’t need SMTP for this anymore. It moved from SwiftMailer to Symfony Mailer,
which resolves transports from a DSN string, and MailKite ships a first-party transport
for exactly that: mailkite/symfony-mailer.
Install it, set one field, and Mautic’s send errors go from a numeric SMTP code to the
API’s own explanation of what actually went wrong.
Why this beats pointing Mautic at SMTP
Generic SMTP gives you a status code and, if you’re lucky, a line of server text. It also means every send is a full protocol round-trip: connect, EHLO, AUTH, MAIL FROM, RCPT TO, DATA. The DSN transport skips the protocol layer and calls the MailKite API directly, and when something’s wrong — an unverified domain, a suppressed recipient, a rate limit — it says so:
Unable to send an email: Can't send yet — domain not verified. (MailKite API status 403).
Compare that to 550 5.7.1 Relaying denied and try to explain to a client why their
newsletter didn’t go out.
Install the transport
composer require mailkite/symfony-mailer
Requires PHP 8.1+ and Symfony Mailer 6.4 or 7.x — both satisfied by any current Mautic 5 install.
Set the DSN
Get an API key from the MailKite dashboard, then set it as
Mautic’s Mailer DSN. Where this lives depends on how your instance is configured — either
.env.local (or wherever your host reads MAILER_DSN) or, on some Mautic installs,
Configuration → Email Settings → Service: DSN:
MAILER_DSN=mailkite+api://mk_live_xxx@default
The API key sits in the DSN’s user slot — there’s no separate SMTP username to invent, and no password field to keep in sync with it. Mautic autoconfigures the transport factory the moment the package is installed; nothing else to register.
Clear Mautic’s cache after changing the DSN:
bin/console cache:clear
Verify your sending domain
The from address on every campaign has to be on a domain with SPF and DKIM published in
MailKite — that’s true whether you’re sending through this transport or plain SMTP, and
it’s the actual determinant of whether Mautic’s mail lands in the inbox or spam. See
mailkite.dev/docs/quickstart if you haven’t set
that up yet.
Test it
Create a test email in the Mautic editor and use Send test. Check the MailKite dashboard’s message log to confirm delivery — if it fails, the error you see in Mautic now comes straight from the API instead of a generic SMTP rejection.
No shell access? Fall back to SMTP
Some managed Mautic hosts don’t give you Composer access. In that case, the plain SMTP path still works — same domain, same API key as the password, just without the honest-error behavior described above:
| Setting | Value |
|---|---|
| SMTP Host | smtp.mailkite.dev |
| SMTP Port | 587 |
| Encryption | TLS (STARTTLS) |
| Username | mailkite |
| Password | Your API key (mk_live_…) |
A note on campaign-scale sending
Symfony Mailer transports — this one included — send one email per request; that’s the
contract every transport follows, not a MailKite-specific limitation. Mautic’s own
campaign/batch layer is what turns a segment send into individual calls, so this doesn’t
change how a campaign send behaves. If you’re calling the MailKite API directly, outside
Mautic, for a very large one-off send, use the PHP SDK’s sendBatch() instead of looping
individual sends.
Troubleshooting
- DSN not picked up — clear the cache (
bin/console cache:clear) after any change toMAILER_DSN. - “User is not set” — the API key has to be in the DSN’s user slot:
mailkite+api://mk_live_xxx@default, notmailkite+api://default. - 535 Authentication failed (SMTP fallback path only) — the password field must be your
mk_live_…API key, not a separate SMTP credential. - Campaign sends but individual test doesn’t (or vice versa) — check that the specific
fromaddress used matches a verified domain; Mautic allows setting different from addresses per campaign.
Full transport reference, the mapping table, and what the transport refuses rather than silently drops: mailkite.dev/docs/integrations/symfony-mailer. Platform-specific config reference: mailkite.dev/docs/integrations/mautic.