Campaigns
Create, schedule, and send email campaigns to your contacts. Track performance with real-time analytics.
Campaign Types
GoodPostal supports several campaign types:
- Regular - Send immediately to selected recipients
- Scheduled - Set a future date and time for delivery
- A/B Test - Try two versions against each other. In Optimize mode GoodPostal sends to a sample of your list first, then automatically sends the winning version to everyone else. In Compare mode it sends different versions to different groups and reports the results side by side.
Creating a Campaign
The campaign wizard guides you through seven steps to create and send a campaign.
- 1
Setup
Name the campaign (this is for your reference only and recipients never see it), pick the campaign type, and add an optional description. - 2
Recipients
Choose one or more contact groups to receive the campaign. You can see the estimated recipient count before proceeding. - 3
Content
Write the subject line and preview text, the two things recipients see in their inbox, then choose an existing template or design the email here. See the templates guide for editor details. - 4
Sender
Choose the verified sender identity this campaign comes from. GoodPostal sends through the email service bound to that sender, falling back to your workspace default, so there is no separate service to pick here. You can switch the service from the campaign detail page if you need to. - 5
Schedule
Send now or turn on "Schedule for Later" and set the date, time, and timezone. A/B test settings live here too. - 6
Review
Check every setting in one place and send a test email. The schedule you picked is shown here for confirmation, but you change it back on the Schedule step. - 7
Send
Launch the campaign with "Send Campaign Now", or "Schedule Campaign" if you set a future send time.
Subject Line Best Practices
- Keep it under 50 characters for mobile compatibility
- Use merge tags for personalization:
Hey {{ first_name }}, check this out. See Merge tags below. - Avoid all caps and excessive punctuation
- Make it specific and action-oriented
- Use the preview text to add context that does not fit in the subject
Merge tags
A merge tag is a placeholder you write into a subject line or into your email content. GoodPostal swaps it for that contact's own value as each email goes out, so one campaign reads differently for every person who gets it. You can write tags in the visual editor and in the subject line, and you can type them by hand in code mode.
Spacing and capitals inside the braces do not matter: {{ first_name }} and {{FIRST_NAME}} do the same thing.
Built-in tags
These are filled in for every workspace with no setup.
| Tag | What it prints |
|---|---|
{{ first_name }} | The contact's first name |
{{ last_name }} | The contact's last name |
{{ full_name }} | First and last name together |
{{ email }} | The contact's email address |
{{ unsubscribe_url }} | This contact's unsubscribe address |
{{ web_view_url }} | A link to read this email in a browser |
{{ company_name }} | Your workspace name |
{{ company_address }} | Your mailing address |
{{ year }} | The current year |
{{ support_email }} | The campaign's reply-to address |
{{ web_version_url }} and {{ view_in_browser_url }} are other names for {{ web_view_url }}. If you are moving from Mailchimp, *|FNAME|*, *|LNAME|*, and *|EMAIL|* keep working as they did.
Your own custom fields
Any custom field on a contact is a merge tag too. A contact carrying sponsor_count fills in {{ sponsor_count }}. Create your fields under Settings > Custom Fields to give each key a name and a type, or read the custom fields guide. A key that arrives without a definition still prints; it is treated as plain text.
In the visual editor, select a text, heading, or button block and the Merge Tags button above the content box lists your custom fields alongside the built-in ones, so you do not have to remember the keys. Code mode has no such button; type the tag where you want it.
Fallbacks
Put a fallback after a vertical bar to cover contacts with nothing stored for that field.
Hi {{ first_name | "friend" }},The fallback is used when the value is missing, empty, or blank. Without one, an empty value simply prints nothing.
Formats
A format changes how a value prints. You may use one format per tag, and it goes before the fallback: {{ key | format | "fallback" }}.
{{ sponsor_since | date:"F Y" }}prints a date your way, for exampleAugust 2026. Without a format, dates follow the format set in Settings > General.{{ lifetime_giving | number:"currency" }}prints$1,250. The other choices areplain(1250) andinteger(1,250).{{ trips | plural:"trip,trips" }}prints just the word, so write the number next to it:{{ trips }} {{ trips | plural:"trip,trips" }}gives1 tripor4 trips.
You can also set a format once per field under Settings > Custom Fields, so every email prints it the same way without repeating the format in your copy.
Showing part of an email only to some contacts
Wrap a section in an {% if %} block and it is sent only to the contacts it applies to. Everyone else gets the email without that section.
{% if sponsor_count > 0 %}
Thank you for sponsoring {{ sponsor_count }} {{ sponsor_count | plural:"child,children" }}.
{% else %}
Would you consider sponsoring a child this year?
{% endif %}You can compare a field against a value:
{% if country == "Haiti" %}matches exactly, letter for letter{% if country != "Haiti" %}matches anything else{% if sponsor_count > 2 %}and{% if sponsor_count >= 2 %}compare numbers{% if sponsor_count < 2 %}and{% if sponsor_count <= 2 %}do the same the other way round{% if is_monthly_donor == true %}compares against a yes or no field
With no comparison, {% if key %} asks whether the field has anything worth printing. It counts as empty when the field is missing, is blank, is the number zero, or is a no on a yes or no field. Anything else counts as filled in.
Blocks may sit inside other blocks, up to ten deep. There is no elsif, and no and, or, or not. To test two things, put one block inside the other.
What happens when a value is missing
- A tag with no fallback prints nothing. A raw
{{ key }}never reaches a recipient. - In a comparison, a missing field is treated as empty text, so
{% if country == "" %}is true for a contact who has no country. - A date GoodPostal cannot read counts as missing, so the fallback applies.
- If a block is left open, GoodPostal stops the send and tells you which one, for example Unclosed {% if sponsor_count %} in your content. Saving a draft mid-edit is never blocked.
A worked example
A win-back email to lapsed donors, using a name fallback, a money format, a date format, and one conditional block.
Subject: {{ first_name | "Friend" }}, your gift is still at work
Hi {{ first_name | "friend" }},
{% if lifetime_giving > 0 %}
Since {{ first_gift_at | date:"F Y" }} you have given
{{ lifetime_giving | number:"currency" }} to this work.
{% else %}
You joined our list in {{ created_at | date:"F Y" }} and have been
reading along ever since.
{% endif %}
{% if sponsor_count > 0 %}
Your sponsorship of {{ sponsor_count }} {{ sponsor_count | plural:"child,children" }} continues every month.
{% endif %}
Would you give again this month?Sending a Test Email
On the review step, click Send Test to send a preview email to yourself. Test emails are rendered and sent through the same pipeline and email sending service as the real campaign, with a test banner added at the top so reviewers can tell it apart from the live version.
Test emails can go to a verified member of this workspace, a verified sender identity, any address on a company domain you already have a verified sender on, or anyone on your test list. The test list lives on the Team page and holds up to 15 addresses; anyone who can edit may add to it, and any address you type into the send-test form is saved there for next time.
Campaign Status
Campaigns move through these statuses:
- Draft - Campaign is being created or edited
- Scheduled - Campaign is scheduled for a future send date
- Sending - Campaign is actively being sent to recipients
- Sent - All emails have been dispatched
- Paused - Campaign was paused during sending
- Failed - Campaign could not start or finish, most often because no sendable recipients were left after unsubscribes, bounces, and complaints were excluded. The campaign detail page explains what went wrong so you can fix it and try again.
- Cancelled - Campaign was cancelled before completion
Recipient Building
When you launch a campaign, GoodPostal builds the recipient list by querying all contacts in the selected groups. Contacts who have unsubscribed, bounced, or complained are automatically excluded. Duplicates across groups are also removed.
The recipient list is built as a background job, so large lists do not block the sending process. You will see a progress indicator on the campaign detail page.
Scheduling Campaigns
To schedule a campaign, turn on Schedule for Later on the Schedule step and pick a date, time, and timezone. The Review step shows the schedule you chose so you can confirm it, and the final Send step launches the campaign with Schedule Campaign instead of Send Campaign Now. Scheduled campaigns can be edited or cancelled before their scheduled send time.
Campaign Limits
Your sending limits are determined by your email sending service's own rate limits. GoodPostal automatically paces large campaigns for reliable delivery, queuing emails at a pace that respects that service's limits. See Send Rates & Limits for the full breakdown.