Email marketing: best practices and unsubscribe
Consent, the unsubscribe link and page, one-click unsubscribe, topics and the practices that keep your broadcasts and automations out of spam.
#Transactional and marketing
Transactional emails respond to an action by the person: an order confirmation, a password reset, a delivery notice. They go out through POST /emails or SMTP and do not look at the audience. Marketing emails are the ones you decide to send: newsletters, promotions, welcome sequences. For these, use broadcasts and automations: Postal honors unsubscribes, filters the suppression list and puts the unsubscribe link and headers in every message.
Unsubscribing and POST /emails
A contact's unsubscribe (unsubscribed) applies to broadcasts and to automation sends, not to POST /emails. If you send marketing through it, check the contact first and respect their choice: the contact.updated webhook tells you when it changes.
#Consent
- Send marketing only to people who asked for it: those who signed up through a form, ticked the option at signup, or are customers and were told. Lists that were bought, rented or scraped from the internet are not allowed by the Acceptable Use Policy and destroy your domain's reputation.
- Turn on double opt-in on public forms: the person confirms the address before joining the audience, which prevents mistyped addresses and bot signups.
- Keep track of where each contact came from (a property such as
source) and when they signed up. Under the LGPD (Brazil's data protection law), you need to be able to show the legal basis for sending. - Someone who only received a transactional email from you has not agreed to receive marketing. Those addresses are added to the audience automatically as unconfirmed contacts and stay out of broadcasts and automations until the owner or an admin confirms that the people agreed, taking responsibility for that consent. See Automatic audience from transactional emails.
- When importing an old list, bring the unsubscribes too (the
unsubscribedcolumn in the mapping) and start with the most recent, most engaged contacts.
#Unsubscribe link and page
Every broadcast or automation email carries a signed link, exclusive to the contact, to the preferences page on the forms host:
https://forms.postal.so/preferencias/019a1e00-1a2b-7c3d-8e4f-5a6b7c8d9e0f?email=019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b&signature=5d1c9a…
On the page, which uses your team's name, the person can:
- leave everything: the contact gets
unsubscribed: trueand no longer receives broadcasts or automation emails; - start receiving again, if they change their mind;
- choose topics: the team's public topics are listed, with the current subscription checked.
The link does not expire, so old emails keep working, and it only works for that contact: if it is altered, it shows “Invalid link” (“Link inválido”, in Portuguese). Each change triggers the contact.updated webhook. In a broadcast, the link is already in the automatic footer; to place it wherever you want, use {{{POSTAL_UNSUBSCRIBE_URL}}} in the HTML (and, in automations, in the template).
Footer and page language
The automatic footer and the preferences page (with the notices it shows) speak the recipient's language, pt-BR or en. Postal chooses for each recipient, using the first one that exists:
- the broadcast's
language(pt-BRoren); - the contact's
languageproperty, such aspt-BRoren-US(the language before the hyphen counts; other languages are ignored); - the contact's
localeproperty, in the same way; - the language the team owner chose in the dashboard;
- Brazilian Portuguese, when nothing says which language it is.
The preferences page uses the same order. The broadcast that counts is the one in the email the person clicked (the link carries the email ID); links from automations and old links, without the broadcast's email, start with the contact. The browser's Accept-Language does not count on these pages. The invalid link page (an altered link, or one for a contact that does not exist) chooses like this: the language of the contact named in the link (the one from its properties or, without it, the team's), then the browser's Accept-Language (pt-BR or en) and, last, Brazilian Portuguese.
To fix the language of a broadcast, send language when you create or update it. Postal does not translate your content (subject, HTML, text): only what it adds itself.
#One-click unsubscribe
All broadcast and automation emails carry the one-click unsubscribe headers (RFC 8058), which the large inbox providers require from bulk senders and use to show the “Unsubscribe” button next to the sender:
List-Unsubscribe: <https://forms.postal.so/preferencias/019a1e00-1a2b-7c3d-8e4f-5a6b7c8d9e0f?email=019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b&signature=5d1c9a…>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
The provider makes a POST to the link with List-Unsubscribe=One-Click and Postal responds 200, without asking for confirmation. The effect depends on where the email came from:
| What the click does | |
|---|---|
Broadcast with topic_id | Removes the contact from that topic only (opt_out). They keep receiving the other topics. |
| Broadcast without a topic | Unsubscribes the contact from everything (unsubscribed: true). |
| Automation email | Unsubscribes the contact from everything. |
For broadcasts, each unsubscribe counts once in stats.unsubscribed and in the unsubscribed metric of GET /emails/metrics.
#Use topics
People who only have the “leave everything” option leave everything. With topics (“News”, “Promotions”, “Content”), a person can stop receiving promotions and keep reading the newsletter.
- Create the topics as
publicso they appear on the preferences page. - Send each broadcast with the
topic_idof its subject: only subscribed people receive it, and the one-click unsubscribe removes the person from that topic only. - Choose the default carefully:
opt_inincludes people who never chose anything;opt_outonly includes those who asked, which is ideal for more frequent subjects.
#Reputation and deliverability
- Use a verified domain and a stable sender, such as
news@. Separating marketing onto a subdomain (for example,news.acmestore.com) protects the delivery of transactional emails. See Domains and DNS. - Grow gradually. On a new domain, start with the most engaged segments and increase the volume over several days. Large sends also pause on their own when the quota runs out and continue when it renews.
- Take care of your list. Permanent bounces and spam complaints go to the suppression list and are left out of future sends. Contacts who have not opened in months deserve a re-engagement broadcast or removal.
- Watch the rates. Postal pauses the team's sending when permanent bounces exceed the limit of the account reputation level (3% to 5%) or complaints exceed 0.3%. A high unsubscribe rate on a broadcast means the subject or the frequency does not suit that segment. The warnings before the pause and how to detect it are in Limits; a broadcast in progress becomes
paused(see the statuses) and only continues after sending is restored. - Test first. Check the preview with a real contact, send a test, write a
preheaderand keep a plain-text version. - Be recognizable. Say in the footer who is sending and why the person is receiving it (“You are receiving this because you signed up at acmestore.com”).
#Measure and react
- Compare broadcasts.
GET /emails/metricswithdimensions=broadcastreturns delivery, open, click and unsubscribe for each broadcast in the period, and the broadcast itself returnsstats. See Metrics and webhooks. - Test one thing at a time. The
experimentstep of an automation splits contacts among 2 to 4 variants (subjects, content, waits), measures opens, clicks, replies and conversions and lets you declare the winner. It depends on the plan. - Listen to replies. With
detect_replies, Postal records each reply (theemail.repliedwebhook) and keeps forwarding it to yourreply_to. See Reply detection. - React to what the person does. An automation can start when the contact opens or clicks an email (
email.opened,email.clicked), receives a tag or changes a property, and thewait_forstep waits for the action for a while before taking another path.
#Sync with your system
If your product also stores the email preference, keep both sides in sync:
- Subscribe to the
contact.updatedwebhook and update your records whenunsubscribedor the topics change. - When the person changes the preference in your product, use
PATCH /contacts/{id}withunsubscribed, orPATCH /contacts/{id}/topics. - Anyone who signs up again through a form starts receiving again, even if they unsubscribed before.