Your transactional emails should not be buried in your codebase

Hardcoded email templates, inline HTML strings and scattered send() calls are a maintenance problem waiting to become a production incident.

What hardcoded transactional emails actually cost you

Every copy change is a deployment

A typo in the payment failed email subject line triggers a pull request, a code review, a merge and a deploy. For a text change.

Email logic is scattered and invisible

send() calls live in billing services, auth controllers, background jobs and webhooks. No one has a complete picture.

Locale and plan variants multiply conditionals

if (user.locale === "de" && user.plan === "Pro") { sendEmail("payment-failed-pro-de-template", ...) } — repeated for every variant.

Template bugs require hotfixes

A broken link or wrong variable in production email templates is an emergency requiring an expedited release.

No audit trail per user

Finding all emails sent to a specific user requires grepping logs across multiple services.

The alternative: event-driven email with external templates

Fire a domain event from your app. else.events handles the routing, templating and delivery.

Templates live outside your repo

Edit copy, swap logos and update CTAs from the else.events dashboard. No deploy required.

Routing logic in rules, not code

Rules match event type, plan, locale and tenant. Your app fires one event; rules decide which template fires.

One integration point

Replace scattered send() calls with a single POST to /api/events. Your app describes what happened, not what to send.

Centralised delivery logs

Every event, every matched rule, every email delivery — in one place with domain context.

// replace your send() calls with this

One event. Every email variant covered.

{
  "type": "invoice.payment_failed",
  "locale": "en",
  "user": { "email": "customer@example.com", "name": "Alex" },
  "data": {
    "plan": "Pro",
    "amount": "29.00",
    "currency": "EUR",
    "update_payment_url": "https://app.example.com/billing"
  }
}

else.events matches this event against your rules (plan = Pro, locale = en) and sends the correct template through your provider. No if/else in your app.

Frequently asked questions

Do I need to rewrite all my emails at once?
No. Start with one email type — for example payment failed. Migrate the rest incrementally. Your existing email code can run in parallel during migration.
Is this only for NestJS or Node.js teams?
No. The API is plain HTTP/JSON. Any backend language or framework can fire an event to else.events.
What about emails that fire from background jobs?
Background jobs can fire events to else.events just like any other part of your application. The event API is stateless and synchronous.
How do we handle email templates that differ by plan or locale today?
Create rules in else.events that match on plan and locale fields in your event payload. One event covers all variants — rules select the right template.

Move your first template out of your codebase

One event replaces a scattered collection of send() calls. Start with the most painful email first.

  • Free during public beta
  • Incremental migration
  • No code change for copy updates after setup