Outbound (SMTP)

Last updated: Jun 22, 2026Section: General

Outbound (SMTP)

Mailoo sends email through three distinct layers. Each layer has different credentials, security boundaries, and intended recipients.

::: {.contents local="" depth="2"} :::

1. Integration SMTP (outboundMail)

What: SMTP settings stored on a specific integration under integration.config.outboundMail (dashboard: Connection & settingsOutbound email (SMTP)).

Who receives mail: End users and business flows for that integration only, for example:

  • Dashboard Create reply to inbound messages (FORM / CONTACT_FORM).
  • Optional welcome email after a new form subscription when an ON_EVENT / SUBSCRIBER_CREATED campaign is configured.
  • Transactional single-recipient send: server-to-server POST …/webhooks/transactional/…/send (scope transactional.send) --- see transactional-email{.interpreted-text role="doc"}.
  • Market email checkout: confirmation email to the buyer after POST …/market/…/orders (same outboundMail as the Market integration that owns the catalog).

API: Owner-only Bearer routes to PATCH integration config / outboundMail and to test SMTP:

POST /api/v1/projects/{projectUid}/integrations/{integrationId}/outbound-mail/test

Supported integration types for this panel and test route: FORM, CONTACT_FORM, and MARKET.

Security: SMTP passwords are stored encrypted (API env MAIL_SMTP_ENCRYPTION_KEY). The API never returns ciphertext or plaintext to clients; responses may include hasSmtpPassword only.

No fallback: If integration SMTP is missing, invalid, or sending fails, Mailoo does not substitute the global mailer. Dashboard Create reply returns an error when SMTP is not configured; welcome emails are skipped and logged when SMTP is unavailable; Market orders return emailToCustomer.status: NOT_CONFIGURED when outboundMail is not set.

See ../../../development/environment{.interpreted-text role="doc"} for variable names.

2. Offer Generator SMTP (separate from outboundMail)

What: Per--offer-generator mail settings in OfferGeneratorMailSettings (not integration.config.outboundMail).

Who receives mail: Wizard submitters (customer delivery) and optional internal notification address configured on the generator.

Why separate: Offer Generator may use different branding, relay limits, or operators than the rest of the Market integration.

This iteration does not merge Offer Generator SMTP with integration outboundMail.

3. Global / platform SMTP (GLOBAL_SMTP_*, GLOBAL_MAIL_FROM)

What: Environment variables on the API host only.

Intended use: Reserved for operator / platform notifications (billing, security alerts, compliance, future system mail). Not used for subscriber-facing mail, Market buyer confirmations, or Offer Generator delivery.

Current product behavior: No user-facing feature depends on global SMTP in this release; configure it when you introduce platform-level mail.

No fallback: Global SMTP is never substituted when integration SMTP fails.

External outbound mail (integrator sites)

Supported: server or BFF calls to Mailoo APIs that create an outbound message inside the integration and let Mailoo send via outboundMail. Examples:

  • Transactional send --- POST …/webhooks/transactional/…/send (transactional.send scope): persists Message, TransactionalSend, subscriber sync, tracking, optional delivery webhooks. See transactional-email{.interpreted-text role="doc"}.
  • Market order create --- buyer confirmation after POST …/market/…/orders.

Not supported: treating Mailoo as a stateless SMTP relay or silent send without Mailoo message records:

  • Do not embed outboundMail SMTP host/user/password in integrator code or public browser bundles.
  • Do not expect a "send this raw MIME now" API with no Message / subscriber / unsubscribe lifecycle.

Integrators that need full control over delivery infrastructure should use their own mailer on the backend. Mailoo's external path is always trigger Mailoo-side processing (audit logs, consent, idempotency), not credential export.

Dashboard test email

On Connection & settingsOutbound email (SMTP), use Send test email to verify the current field values (you do not have to save first). Mailoo sends one message to your Mailoo account email (the signed-in user). Nothing is persisted by the test alone; saving still uses Save SMTP settings.

If the API host is missing MAIL_SMTP_ENCRYPTION_KEY and you enter a new SMTP password in the form, save and test return 503 with a clear configuration message---set the key on the API (same value on every replica), e.g. openssl rand -base64 32.

Owner API (optional)

Same as the dashboard test: POST /api/v1/projects/{projectUid}/integrations/{integrationId}/outbound-mail/test with Bearer auth; body { "outboundMail": { … } } matches the PATCH outboundMail field shape.