Looking to go the other way, designing in Brew and sending from SendGrid? See the SendGrid integration instead.
Concepts
Check These Limits First
Brew doesn’t yet match three things SendGrid’s Email API does. If your integration depends on any of them, keep that mail on SendGrid for now and move marketing first.1. Export Contacts, Consent, and Suppression
Contacts. Go to Marketing → Contacts. Click the action menu (⋮) next to All Contacts, or next to one list, then click Export. SendGrid emails you when the file is ready. Download it from the Active Exports page within 12 hours of starting the export. Keep these columns:- Email, first name, last name, and any custom fields you use
- Any custom field that records how or when someone opted in
A block is about your sending IP or your content, not the address. SendGrid doesn’t suppress blocked addresses, so don’t import them as opt-outs. Read the block reasons instead.
On SendGrid, a global unsubscribe, bounce, or spam report stops every send to that address, transactional mail included. Brew splits the two:
Subscribed: falsestops marketing only. Transactional mail from a transactional-purpose domain still reaches the contact. That’s what you want for a password reset.- Brew can’t import a bounce as a suppression. It suppresses an address after one of its own sends hard-bounces. Fix or remove bounced and invalid addresses in your own user records before you move transactional mail.
Decide Where Group Opt-Outs Go
Each SendGrid unsubscribe group is one kind of mail, such as a newsletter or product updates. Brew has no groups. Opt-outs work at two levels. Each marketing domain keeps its own unsubscribe list, and Unsubscribe from all covers them all. See Unsubscribes. Map each group before you import:
A global unsubscribe always maps to the brand-wide opt-out.
2. Map Your CSV
Notes:
- SendGrid’s export has no consent column. Brew reads opt-outs only from a
Subscribedcolumn, so add one to each suppression file before you import it - SendGrid’s activity columns, such as last opened and last clicked, import as plain properties and stop updating on the day you export. Drop the ones you won’t filter on
- New columns become camelCase properties. A
plan_typecolumn becomesplanType. Use that name in merge tags and filters - Empty cells don’t overwrite existing data on update imports
- Duplicate rows: the last one wins, so dedupe first
- These names belong to built-in contact fields and can’t be used for custom properties:
email,firstName,lastName,subscribed,createdAt,updatedAt,validationStatus,lastValidatedAt,importId,csvFileName - Save as UTF-8. Garbled characters at the mapping step usually mean it wasn’t
- Dates: day-first dates such as
03/04/2026(3 April) import correctly when you pick day first at the mapping step, andYYYY-MM-DDneeds no choice. See date formats
3. Import into Brew
Audience → Add contacts → CSV Upload. Map columns, review, then import. Tick the validation checkbox first if the list hasn’t been checked recently. It costs 2 credits per address, which is worth it before warming up a new domain. Upload the contact file and each suppression file separately. That keepsSubscribed set correctly per batch.
Then import each group’s opt-outs into the domain you chose in Step 1. Open Domains in the sidebar, pick the domain, click View list on its Unsubscribes card, then Import CSV.
Each file takes up to 10,000 rows. See Import a List from Another Provider.
Import contacts before the group files. An address that isn’t a contact yet can end up opted out of all mail, not just one domain.
Bring Your Consent Records
A contact’sSubscribed status says Brew may email them. A consent record says how and when they agreed. Carry both over.
- Export the evidence. SendGrid stores no consent record. If you saved an opt-in date or source in a custom field, keep that column as a custom property.
- In the app, tick the consent checkbox at the review step. Brew records consent once for the whole file, dated the day you import.
- To keep each person’s original opt-in, import over the API instead.
POST /v1/contactstakes aconsentrecord per contact, with the original date ascapturedAt. It never changesSubscribed.
4. Rebuild Segmentation
Audiences are dynamic filters over contact properties, email engagement, and subscription status. Describe one in plain English or build the filters by hand. SendGrid segments filter on contact fields, email activity, and Single Send or Automation activity. Contact fields carry over as properties. Activity starts fresh in Brew, so a segment like “opened in the last 30 days” refills as you send. Lists don’t have a direct equivalent. Rebuild each list as a custom property plus an Audience filtered on it. Add a column to that list’s export, such asnewsletterList set to true, and import it.
Keep marketing to people who opted in. A fire for a new address creates a subscribed contact. Once receipts and resets run through Brew, your audience fills with customers who never chose marketing. Build every marketing Audience on a property only opted-in contacts carry, such as marketingOptIn: true from your import.
Before cutover, spot-check that a recreated Audience’s membership count is in the right ballpark against the original segment. A wrong translation can undercount or overcount who gets an email, and that isn’t always visible in the UI.
5. Rebuild Templates and Merge Tags
To get a dynamic template’s HTML, open Email API → Dynamic Templates in SendGrid, then the template’s active version. In the Design Editor, the Build tab’s Advanced section exports the HTML. In the Code Editor, copy it.
From code,
GET /v3/templates/{template_id} returns each version’s html_content.
In Brew, open Emails in the sidebar, then use the import tools in the toolbar right of the canvas. See Importing existing designs.
For most templates, use the HTML or screenshot as reference. Prompt Brew to rebuild it against your brand rather than treating the import as finished. It’s faster, and the result inherits your brand identity automatically.
Running a long parallel test instead of a fast cutover? You can design in Brew and still send from SendGrid.
Click Send in the top right, choose Export template, and pick SendGrid. That pushes the finished email to SendGrid as a dynamic template through the SendGrid integration.
Translate Merge Tags
SendGrid dynamic templates use Handlebars. Brew runs Liquid. Both use{{ }} for values, but logic blocks look different.
Brew property names are camelCase and case-sensitive, and a snake_case name renders empty.
If you keep an imported template’s HTML as it is, replace SendGrid’s tags before you send:
{{first_name}}becomes{{ firstName }}, and{{last_name}}becomes{{ lastName }}. A custom field becomes the camelCase name from your import, such as{{ planType }}.{{insert first_name "default=there"}}becomes{{ firstName | there }}. The fallback after the pipe shows for contacts with nothing on file.- Values from
dynamic_template_databecome{{ trigger.* }}, named after the key you send in the fire’spayload.{{order.number}}becomes{{ trigger.order.number }}. See Step 7. {{#if}},{{else if}},{{else}}, and{{/if}}become{% if %},{% elsif %},{% else %}, and{% endif %}.{{#unless}}becomes{% unless %}.- Comparison helpers become operators inside
{% if %}.{{#equals a b}}is{% if a == b %}, andnotEquals,greaterThan, andlessThanare!=,>, and<.{{#and}}and{{#or}}becomeandandor. {{#each order.items}}{{this.name}}{{/each}}becomes{% for item in trigger.order.items %}{{ item.name }}{% endfor %}. Inside the loop, write the full path where Handlebars used@root.{{formatDate}}and{{length}}become Liquid filters, such asdateandsize. Check each one against the Liquid templating reference.- Triple braces, such as
{{{name}}}, are a legacy spelling in Brew. Rewrite them with two braces. - Legacy substitution tags, such as
-name-sent insubstitutions, become{{ trigger.name }}from the fire’spayload. - Delete
{{{unsubscribe}}},{{{unsubscribe_preferences}}}, the<%asm_...%>tags, and the{{Sender_Address}}family. Brew adds the unsubscribe link and your mailing address to every marketing email. Transactional mail carries no unsubscribe link. - Remove
{{Weblink}}, the view-in-browser link.
6. Rebuild Automations
Marketing Campaigns automations become Brew automations on a marketing-purpose domain.
Transactional email. Most SendGrid mail is a Mail Send call with a dynamic template, like a receipt. In Brew, the sending domain decides what’s transactional.
Rebuild each template as a trigger plus a one-step automation on a transactional-purpose domain. One trigger per kind of email. See Transactional Email.
Test-fire before publishing. Leave every rebuilt automation unpublished until cutover day, which is what prevents a double-send. Build an Automation covers the trigger setup and the test step.
7. Swap the API Calls in Your Code
SendGrid’s v3 API lives athttps://api.sendgrid.com/v3 and takes a bearer key. Brew does too, at https://brew.new/api/v1.
Contact upsert.
Before, with SendGrid:
202 with a job_id. Brew takes custom fields by name. A list becomes a custom property, as in Step 4.
Adding someone to a SendGrid list opts no one in. In Brew, subscribed: true opts the person in, and the consent record says how. The consent record never changes subscribed.
subscribed: true applies only to a new contact. A single upsert that asks for it on an opted-out contact gets 422 RESUBSCRIBE_NOT_ALLOWED, and nothing is written. Handle that 422 by sending the same call without subscribed.
Transactional sends. A Mail Send call becomes a fire. Fire the trigger, and its published automation sends the email.
Before, with SendGrid:
to address becomes the payload’s email, the contact the automation runs for. dynamic_template_data becomes the payload, read in the email as {{ trigger.order.number }}. The template, sender, and subject move into the automation, so template_id, from, and asm leave your code.
Nest order data in an object, as above. Object and array fields stay template data. Declared top-level values, such as firstName, are saved on the contact.
Fire once per recipient. A Mail Send call with several personalizations becomes several fires, each with its own key. Each fire counts toward the rate limit in Check These Limits First.
SendGrid’s Mail Send takes no idempotency key, so a retry can send twice. On Brew, send an Idempotency-Key derived from the action, like the order id above.
A repeat with the same key starts nothing new. See Idempotency.
A fire answers 202 once its runs start, not when the email is delivered. A suppressed address counts under counts.skipped. 422 NO_PUBLISHED_AUTOMATION means nothing published listens for the trigger, so publish before you point code at it.
Full request shapes are in the API reference. This section shows the shape of the migration, not a copy-paste replacement for your code.
8. Cut Over
Move in this order:- Rebuild while SendGrid keeps sending. Import contacts and rebuild segments, templates, and automations. None of it touches live sending. Keep every Brew automation unpublished.
- Check your segments. Confirm each recreated Audience’s membership count against the original. See Step 4.
- Refresh opt-outs. Right before your first Brew send, export SendGrid’s new global unsubscribes, bounces, invalid emails, and spam reports and import them into Brew as
Subscribed: false. Export the group unsubscribes again too. Repeat before each type you move, until SendGrid stops sending. Anyone who opted out during the rebuild stays opted out. - Warm up with the first type you move. Pause that type on SendGrid first, so nobody gets it from both. Send to your most engaged contacts first and ramp over several days. Gradual send does the ramping for you. No history means no reputation, even on a verified domain.
- Move one type at a time. Single Sends first, then automations. For each automation, in order: disable it on SendGrid, publish the Brew automation, then point its signup forms or app events at Brew. Watch each in analytics before you move the next.
- Move transactional email last, and only mail the limits in Check These Limits First don’t block. Before you move any, add a separate transactional-purpose subdomain (see Transactional Email). A fire for a new address creates a subscribed contact, so only send marketing to people who opted in. Order confirmations and resets are the highest-stakes sends. Cut them over one at a time, and test-run each automation with a real payload before you point production code at its trigger.
- Keep SendGrid as a fallback. Leave its API key and templates in place for a couple of weeks, so you can switch a code path back. Then downgrade or cancel.
Quick Reference
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.
Ask ChatGPT or Claude
Click here to open the Copy page menu at the top of this page, then send the page to ChatGPT, Claude, or your editor.