DEV Community

Bucabay
Bucabay

Posted on • Originally published at mailkite.dev on

Mautic email deliverability: replace SMTP with the Symfony Mailer DSN transport

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).
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 to MAILER_DSN.
  • "User is not set" — the API key has to be in the DSN's user slot: mailkite+api://mk_live_xxx@default, not mailkite+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 from address 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.


Originally published at mailkite.dev.

Top comments (0)