Guide

Custom Preference URLs

Brand the preference-center link recipients click in the email body, while ArtaMail continues to sign tokens and process consent. You can keep Gmail one-click on ArtaMail, or move everything to your own domain.

Choose an approach

Approachpreferences_url_templateBody linksList-Unsubscribe
Hybrid (recommended)Leave emptyCustom URL + {{unsubscribe_token}}ArtaMail /api/u/{token} (one-click works out of the box)
Default ArtaMailLeave empty{{unsubscribe_url}}Same ArtaMail URL
Full custom domainSet (e.g. https://prefs…/manage?token={{token}}){{unsubscribe_url}} uses your templateSame custom URL — you must proxy GET and POST
One setting drives both body and header
When you set preferences_url_template, it applies to {{unsubscribe_url}}, typed {{unsubscribe_<slug>}}, and the List-Unsubscribe header. There is no separate toggle for Gmail one-click. If you only want a branded "Manage preferences" link in the email body, leave the setting empty and use the hybrid recipe below.

Hybrid: custom manage link + ArtaMail one-click

Best when you host your own preference UI but do not want to implement a one-click POST proxy. Recipients see your domain in the email; mail clients (Gmail, etc.) still POST to ArtaMail for RFC 8058 one-click unsubscribe.

  1. In Settings → Subscription consent, leave Custom preferences URL empty.
  2. In marketing templates, build your manage link with the bare token (do not rely on {{unsubscribe_url}} for branding — that variable follows the org template or ArtaMail default):
html
<a href="https://app.example.com/preferences?token={{unsubscribe_token}}">
Manage email preferences
</a>

Your page reads the token, loads data from ArtaMail, and saves preferences via the APIs below (GET data + POST preferences). You do not need a POST handler for List-Unsubscribe — that stays on https://artamail.artatol.net/api/u/{token}.

Typed links
For a preference page scoped to one subscription type, use {{unsubscribe_token_<type_slug>}} the same way.
Click tracking
Links whose URL contains unsubscribe or /u/ skip click tracking. If your path is something like /preferences, the href may be rewritten through the click tracker (GET still reaches your page after redirect). Prefer a path that includes unsubscribe if you want to skip tracking entirely.

Full custom domain (optional)

Use this when you need a white-label URL in both the email body and List-Unsubscribe (same domain everywhere). In Settings set a template such as:

text
https://prefs.acme.com/manage?token={{token}}

At send time ArtaMail replaces {{token}} with a signed HMAC token. That URL is used for {{unsubscribe_url}} and for List-Unsubscribe. This setting is unrelated to double opt-in success redirects (those use per-template confirm_success_redirect_url).

Multiple products
Prefer a separate ArtaMail account per brand and set preferences_url_template on each account when you want a fully custom domain per product. See the Multiple Products guide. For shared contacts in one account, see shared contacts (advanced).

Template variables

VariableReplaced with
{{unsubscribe_url}}Full preference URL — org preferences_url_template or ArtaMail default (also used for List-Unsubscribe)
{{unsubscribe_<type_slug>}}Full URL scoped to a subscription type (same org template rules)
{{unsubscribe_token}}Bare signed token — build your own body URL (hybrid pattern)
{{unsubscribe_token_<type_slug>}}Bare typed token for a subscription type

APIs for your preference page

Whether you use the hybrid or full-custom approach, the preference UI on your domain loads and saves consent through ArtaMail. Token verification and consent updates stay on our side.

GET — load preference data

Users click links in the email body. Your page should read the token from the query string or path, then:

http
GET https://artamail.artatol.net/api/u/{token}/data

Response includes locale, resolved copy (all page strings for the contact's language), optional oneClickCopy, orgName (brand), legalEntityName, and localized subscription subtypes. Use copy.title, copy.button_save, etc. in your UI — or use ArtaMail custom HTML with placeholders like {{title}}. Full reference: Preferences Data API.

Example response

json
{
"orgId": "550e8400-e29b-41d4-a716-446655440000",
"orgName": "SuperWidget",
"legalEntityName": "Acme Holdings s.r.o.",
"email": "[email protected]",
"locale": "cs",
"copy": {
"title": "Předvolby e-mailu",
"subtitle": "Vyberte, jaké e-maily chcete dostávat.",
"footer": "Powered by ArtaMail",
"button_save": "Uložit předvolby",
"button_unsubscribe": "Odhlásit se ze všeho",
"type_title": "Předvolby e-mailu"
},
"oneClickCopy": {
"success_title": "Odhlášeno",
"success_message": "Byli jste odhlášeni z našeho seznamu."
},
"type": null,
"subtypes": [
{
"id": "subtype-uuid",
"slug": "weekly-digest",
"typeSlug": "newsletter",
"label": "Týdenní přehled",
"channel": "marketing",
"sortOrder": 0,
"subscribed": true
}
]
}

Subtype labels are already localized. Save changes with POST /api/u/{token}/preferences (subtype slugs as JSON keys).

POST — mail client one-click (full custom domain only)

Required only when preferences_url_template is set. Gmail and other clients send an RFC 8058 one-click unsubscribe POST to the URL in the List-Unsubscribe header — the same custom URL you configured. Your server must accept that POST and proxy it to ArtaMail:

http
POST https://artamail.artatol.net/api/u/{token}
Content-Type: application/x-www-form-urlencoded
List-Unsubscribe=One-Click
Do not skip the POST handler
If your custom URL only serves a GET landing page, one-click unsubscribe from mail clients will fail even though in-email links work. Optional: proxy POST with ?redirect=1 to show a localized success page at /preferences/{token}?one_click=1 (uses org one_click_copy). With the hybrid approach, leave the template empty so this POST stays on ArtaMail.

ArtaMail hosted UI

Default landing after GET /api/u/{token} is /preferences/{token}. Legacy /unsubscribe/* URLs redirect permanently.

Custom HTML templates

On subscription types with custom HTML, wrap form-only sections (header, intro, footer) in artamail-form-only so they hide after save. Success content lives in #artamail-success inside {{subtypes_form}}. Optional post-save CTA: {{success_button}} or class artamail-success-cta ({{success_button_class}}). Injected and {{success_button}} links use target="_top" so navigation leaves the hosted iframe. If you build your own <a> with {{success_button_href}}, add target="_top" as well.

Example reverse proxy (Node) — full custom domain

Only needed when List-Unsubscribe points at your domain (preferences_url_template is set).

prefs-proxy.ts
// POST /manage?token=... → ArtaMail one-click unsubscribe
export async function POST(req: Request) {
const token = new URL(req.url).searchParams.get('token');
if (!token) return new Response('Missing token', { status: 400 });
const body = await req.text();
const res = await fetch(`https://artamail.artatol.net/api/u/${token}`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body,
});
return new Response(null, { status: res.ok ? 200 : res.status });
}