nti/email-bundle
nti/email-bundle is a Symfony bundle for working with application emails. It provides reusable components for composing and sending messages, integrating email workflows into Symfony projects and helping centralize email logic. Use it to streamline transactional email setup and keep email code organ...
Before writing a line of code, read the source. This bundle is small (2 stars, 0 dependents), so the README and src/ are the only authoritative docs you have.
nti/email-bundle; verify with composer show nti/email-bundle before committing it to composer.json. Now that a 5.5.x line exists with patch releases, ^5.5 is defensible — but check the changelog for the 5.x breaking changes first. If you started on a 2024-04-24-style tag, plan the 5.x upgrade deliberately.config/bundles.php (Symfony Flex may not auto-register given the low profile):
NTI\EmailBundle\NTIEmailBundle::class => ['all' => true],
vendor/nti/email-bundle/DependencyInjection/Configuration.php for the real config tree — do not guess YAML keys. Expect something like:
# config/packages/nti_email.yaml
nti_email:
mailer: mailer.mailer # or a dsn
templates: '%kernel.project_dir%/templates/emails'
persist: true # if it ships Doctrine entities
bin/console doctrine:schema:validate and check Entity/ (or Model/) for Smtp. If the bundle ships no migrations, generate your own — an unmigrated SMTP table is the most likely cause of a blank/failing first send.NTI\EmailBundle\Mailer\EmailManager or an EmailFactory + EmailSender pair) into a controller or command and dispatch one email through your local MAILER_DSN. That two-minute smoke test tells you more than the README about how the pieces fit.symfony/mailer), resolves SMTP settings from the DB table, or has its own transport. bin/console debug:container --tag=mailer.transport_factory and bin/console debug:container NTI will show what it registers.Start in vendor/nti/email-bundle/ — read Resources/config/services.yaml, the DependencyInjection/ folder, and any Entity/ or Model/ directory. Those three tell you whether it is a thin Mailer wrapper, a DB-backed template/queue system, or an admin-facing email store.
Wrap, don't reach in. Inject the bundle's sending service into your own App\Mail\Notifier (or similar) rather than calling it from controllers. That one seam lets you swap the bundle out if it is abandoned, and keeps your domain code free of a 2-star dependency.
Treat the DB SMTP table as configuration state, not code. The 5.5.2 fix makes clear SMTP settings live in a table and are read at send time. That means:
Secure the SMTP credentials. A table holding host/user/password is a compliance surface. Encrypt the password column at the application layer, restrict the table to the app's DB user, and never expose it via an admin route without an authorization check the bundle does not provide.
Template resolution. Most small Symfony email bundles resolve templates from the filesystem and optionally fall back to a DB-stored template. If the bundle supports both, choose one convention per project — DB-stored templates are great for marketing copy but painful for version control and code review of transactional emails.
Async sending via Messenger. If the bundle exposes the underlying Symfony\Component\Mailer\MailerInterface or a message object, route sends through Messenger (SendEmailMessage) so a slow SMTP server does not block a request. If it only has a synchronous send(), wrap that call in your own Message + MessageHandler — you get retries, throttling, and a dead-letter queue without modifying the bundle.
Persist-then-send for auditability. If the bundle ships entities for storing emails (look for Doctrine\ORM\Mapping\ attributes or Resources/config/doctrine/), enable persistence and run migrations for its schema. This is the most likely reason the bundle exists — a record of every outbound email for support and compliance. Pair it with a small listener that on MessageSentEvent / failure updates the record's status.
Compose DTOs at the boundary. Build an EmailMessage DTO (to, template, variables, subject) in your app, then map it to whatever the bundle expects. Avoid passing bundle-specific objects past your service layer.
Integrations to wire explicitly:
MAILER_DSN; confirm the bundle honors it rather than a hardcoded SMTP.Notifier-style adapter if the bundle predates Symfony's symfony/notifier — you get channel abstraction for free.symfony/mailer's null:// DSN or a MessageLoggerListener; integration-test with a MailHog/mailpit container.Multi-tenant use. If you serve multiple tenants, the template directory, DB templates, and the SMTP rows need scoping; do it in your service layer, not by relying on a bundle feature that likely does not exist.
5.5.2 patch line is mildly reassuring — someone is maintaining it — but a version number alone is not a support contract. Pin the version, vendor a copy if licensing permits (MIT — it does), and have a plan to replace it. Budget for reading the code when a Symfony upgrade breaks it.TableNotFoundException, a query builder error, or an unexpected transport, apply the patch before debugging your own code. Diff Entity/Smtp* and its repository between your version and 5.5.2 — schema or method-name changes are the usual culprits and may require a migration.composer.json pins the April 2024 release, you are missing whatever the 5.x line fixed, including this SMTP table bug. Read the 5.0 changelog for BC breaks before jumping — a major bump on a small bundle is often a rename-everything release.Configuration.php tree is your only schema. Run bin/console config:dump-reference nti_email after registration to see every key with defaults — this one command replaces most of the missing docs.config:dump-reference and the Entity/ folder, and generate your own migration if the bundle ships none. Missing migrations is the most common cause of a "bundle does nothing" bug on first install, and now the most common cause of a "transport not configured" bug too.__construct(EmailManager $m) fails with "cannot autowire." Fix by aliasing in your services.yaml:
NTI\EmailBundle\Mailer\EmailManager:
alias: nti_email.manager # verify the real service ID via debug:container
symfony/mailer semantics. If the bundle ships its own transport or SwiftMailer-era code, MAILER_DSN, From headers, and attachments may behave differently. The DB-backed SMTP row may silently override MAILER_DSN — test both paths to learn which wins. Verify one email per feature (HTML, plain text, attachment, reply-to) on install.bin/console debug:config nti_email, debug:container NTI, debug:event-dispatcher | grep -i email, doctrine:schema:validate, and set MAILER_DSN=null://null to isolate whether failures are bundle-side or transport-side. For this release specifically, dump the SMTP row you expect to be used and confirm the repository returns it.Interface in src/ and any CompilerPass in DependencyInjection/. Those are your customization hooks — a template resolver interface, a sender interface, or an SMTP provider interface is the usual set. If there is none, decorate the bundle's service in your own services.yaml (decorates:) rather than forking.SmtpSetting model.App\Mail layer on day one. The two-hour investment to wrap it is what makes the low adoption score tolerable.How can I help you explore Laravel packages today?