Get your API key
All integrations PHP

Symfony Mailer + MailKite

Symfony Mailer resolves transports from a DSN string. This package makes mailkite+api:// a valid one — install it, set a single env var, and every MailerInterface::send() in a plain Symfony app, or in anything else built on Symfony Mailer, delivers through MailKite's Send API. No SMTP round-trip.

What you need

  • A verified domain with SPF + DKIM published
  • Your API key (mk_live_…)
  • PHP 8.1+ and Symfony Mailer 6.4 or 7.x

Install

terminal
composer require mailkite/symfony-mailer

Configure

Set your Mailer DSN — the API key goes in the DSN's user slot:

.env
# .env / MAILER_DSN
MAILER_DSN=mailkite+api://mk_live_...@default

In a standard Symfony app with symfony/framework-bundle, that's it — Symfony's mailer autoconfigures any installed transport factory. The from domain must be verified (SPF + DKIM) on your MailKite account.

No framework DI?

Build the transport directly:

bootstrap.php
use MailKite\Mailer\Transport\MailKiteTransportFactory;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mailer\Transport\Dsn;

$transport = (new MailKiteTransportFactory())->create(
Dsn::fromString('mailkite+api://mk_live_...@default')
);
$mailer = new Mailer($transport);

Send email

send.php
use Symfony\Component\Mime\Email;

$email = (new Email())
->from('hello@yourdomain.com')
->to('ada@example.com')
->subject('Your invoice #1042')
->html('<p>Thanks!</p>')
->text('Thanks!');

$mailer->send($email);

Mautic

Mautic 5+ runs on Symfony Mailer with a DSN field in Configuration → Email Settings, and it consumes any transport installed via Composer — install this package alongside Mautic, then set:

Mautic config
# Mautic: Configuration → Email Settings
mailkite+api://mk_live_...@default

Full walkthrough (SMTP fallback for managed hosts without shell access): mailkite.dev/docs/integrations/mautic.

What maps where

Symfony EmailMailKite sendNotes
from, to, cc, bccfrom, to, cc, bccdisplay names preserved
subjectsubjectomitted when null
HTML + text bodieshtml, textresource bodies read to string
reply-to (single)replyTo2+ addresses throws — API takes one
In-Reply-To headerinReplyTothreading
attachmentsattachments[]base64 content + filename + contentType

Honest failures, not silent drops

The MailKite send API carries a fixed envelope, so the transport throws a TransportException (with the API's own error message) instead of pretending:

  • API errors (unverified domain, suppressed recipient, rate limit, …) surface verbatim with their HTTP status.
  • Custom headers the API can't deliver are refused, not dropped.
  • Inline (cid:-embedded) images are refused — host the image at a URL instead.
  • Multiple reply-to addresses are refused — the API takes one.

Batch sending

Symfony-provided transports send one email per request, and this one does too — doSend() is per-message by contract. For high-volume sends, call the PHP SDK's sendBatch() directly rather than looping the transport.

Laravel

Using Laravel? Install mailkite/laravel instead — it wraps this same transport with MAIL_MAILER=mailkite and Laravel's config conventions.

Troubleshooting

  • DSN not picked up — clear the app cache after changing MAILER_DSN (bin/console cache:clear in Symfony, or Mautic's equivalent).
  • "User is not set" (IncompleteDsnException) — the API key must be in the DSN's user slot: mailkite+api://mk_live_xxx@default, not just mailkite+api://default.
  • Custom-header exception — the API can't carry arbitrary SMTP-style headers; remove tag/metadata headers before sending, or move that data into your own logging.

See the SMTP relay docs for the plain-SMTP path, or all integrations for other platforms.