The Domain Decides
In Brew, a transactional email is an automation. There is no separate transactional email object to create. What makes an automation transactional is the sending domain. A domain withsendingPurpose: 'transactional' removes the unsubscribe requirement and delivers to unsubscribed contacts. The same automation on a marketing-purpose domain is a marketing send that respects unsubscribes. You pick the class by picking the domain.
Automations on marketing-purpose domains still cover the marketing side of event-driven email: welcome flows, onboarding, abandoned cart, win-back. Those respect unsubscribes, which is what you want for marketing, and not what you want for a password reset. That is why a reset flow’s send step belongs on a transactional-purpose domain.
Set It Up
1
Add a transactional domain
Add a sending domain with the Transactional purpose in the Brew app, or from code with
POST /v1/domains and sendingPurpose: "transactional". The MCP create_domain tool adds marketing domains only. Verify Your Sending Domain covers the DNS records and both purposes. Run marketing and transactional mail on separate subdomains.2
Create the trigger
Build a custom trigger, or use one an integration provisions. Declare the payload fields the email needs. Build an Automation covers triggers and payload contracts.
3
Build and publish the automation
Wire the trigger to an automation. Point its Send Email step at the transactional domain, then publish.
4
Fire it from your product
Send the event from your backend, as shown below.
Fire It from Your Product
Fire the trigger with a JSONpayload (nested objects and arrays supported). Reference payload fields in the email as {{ trigger.* }} variables:
{{ trigger.resetUrl }}. The payload’s email field is the contact the automation runs for. Merge Tags covers the variable syntax.
What to Know Before You Ship One
- Suppressed addresses are skipped. A fire to a hard-bounced address answers
202withcounts.skipped: 1and starts no run. The events feed records why. - A fire for a new address creates a contact. It’s subscribed, like a contact added with only an email. Send that person marketing only if they opted in.
- Keep one-time codes off the contact. Nest them in the payload, such as
{ "verification": { "code": "482913" } }, and write{{ trigger.verification.code }}. A nested value renders but isn’t saved on the contact. - The subject line is stored. The events feed keeps each email’s subject, so put a code in the body, not the subject.
- Tracking still applies. Click and open tracking follow the domain’s settings, so links go through the tracking domain and an open pixel is added.
- Retries don’t send twice. Send an
Idempotency-Keyheader with a stable value per event, such as the reset request’s ID. A retry with the same key answers with the original runs instead of sending again. - Redact secrets in logs. In the trigger’s payload schema, set
pii: "high"on fields such as codes and reset links. Brew then hides their values in execution logs and the inbound log. - Encode values inside links. A token with
+or&breaks in a raw link. Write{{ trigger.reset.token | url_encode }}, or pass the whole link already encoded. See Merge Tags. - MCP won’t fire to a contact who opted out of marketing. The email itself has no unsubscribe link, but an agent still can’t send it to that contact.
fire_trigger_eventanswersRECIPIENT_UNSUBSCRIBEDeven for a transactional automation. Fire receipts and resets from your backend over the API.
Change a Domain’s Purpose
PATCH /v1/domains/{domainId} with sendingPurpose changes a domain’s purpose. Published automations on that domain follow the new purpose on their next send. After a switch to transactional, they send with no unsubscribe link and reach unsubscribed contacts.
Emails can’t send from a transactional domain. If one still points at the domain, it’s blocked at send time.
Next Steps
Need Help?
Our team is ready to support you at every step of your journey with Brew. Choose the option that works best for you:- Self-Service Tools
- Talk to Our Team
Search Documentation
Type in the “Ask any question” search bar at the top left to instantly find relevant documentation pages.
ChatGPT/Claude Integration
Click “Open in ChatGPT” at the top right of any page to explore it further with ChatGPT or Claude.