Lifecycle e-mails: member reactivation
Myra AI Workspace can send a short series of service e-mails to workspace members who never sent a first message after being invited, or who stopped using the workspace. The goal is active seats, not marketing: every mail is about the recipient's own contracted workspace seat, carries a one-click opt-out, and is sent from the platform's customer-success mailbox — never from a customer's address.
This page is the complete reference: the switches, who is contacted and when, every mail, the opt-out, the metrics, and what is deliberately not done.
Two switches
| Switch | Who sets it | Default | Where |
|---|---|---|---|
Platform switch reactivation_emails_enabled |
Platform admin | on — the feature shipped dark; migration 0337 turned the switch on in every deployment (2026-09-29). Off remains the incident brake | Organisations → Feature Flags, or PUT /admin/v1/settings/reactivation_emails_enabled |
Tenant setting reactivation_emails_enabled (tri-state) |
Tenant admin or platform admin | Auto (on) for self-serve trials, Off for enterprise tenants until enabled per tenant — see Defaults by plan | User Management → Tenants → (tenant) → Edit → General → Reactivation e-mails to inactive members, or PATCH /admin/v1/tenants/:id |
A mail is only ever sent when both are on. The platform switch is the incident brake: turning it off stops every reactivation mail everywhere on the next sweep.
Auto resolves to on when all of the following hold, otherwise off:
- the tenant's plan is
enterprise, or the tenant is on a trial (trial_ends_atset and not yet passed); - the tenant has at least one gateway with
purpose = production; - the tenant is not a test fixture — the ids of the seeded e2e tenants (
00000000-e2e…), thee2e-syntheticandmyratestslugs, and any slug starting withe2e-are never auto-enabled.
An explicit On overrides the fixture rule (that is how an end-to-end test enables the cadence
on a fixture tenant). An explicit Off overrides everything. The tenant editor shows what Auto
currently resolves to ("Auto — currently on/off"). Every change is audited
(tenant.reactivation_emails_enabled_changed, before/after; auto is written for the unset
state).
Defaults by plan
What a tenant's tri-state holds when nobody has touched it depends on the plan (CEO decision 2026-09-29, migrations 0337 and 0342):
| Plan | Stored default | Effect |
|---|---|---|
self_serve_trial |
unset (Auto) | On while Auto's conditions hold — the trial is unexpired, the workspace has a production gateway and is not a fixture. A tenant admin can opt the workspace out at any time (Off); that choice is honoured from then on. Migration 0342 reset the blanket Off that 0337 had written on existing self-serve trials back to Auto — including any Off set by hand on a self-serve trial before 0342 ran (none existed: the cadence had never run for them). |
enterprise (including POCs — enterprise with a trial_ends_at) |
explicit Off (migration 0337) | Off until a platform admin or the tenant admin enables the workspace — set it to On, or clear it to Auto. Arming an enterprise customer is a separate, per-tenant decision. Enterprise tenants created after 0337 start as Auto (on, given Auto's conditions). |
every other plan (free, standard, …) |
unset (Auto) | Off — Auto only resolves to on for an enterprise plan or an unexpired trial. |
myratest (mail fixture) |
explicit On (migration 0337) | On — overrides the fixture rule so the cadence can be exercised end to end. |
Who is contacted, and when
Activity means a chat turn or a gateway request made by the member (request_log.user_id,
or a user message in one of the member's conversations). Signing in is not activity — the
observed pattern this feature addresses is "logged in once, never sent a message".
Members are classified on every sweep:
| State | Condition | Sequence |
|---|---|---|
| Never started | No activity ever, and the seat is at least 3 days old (younger than 45 days) | never-activated, 3 mails |
| Inactive (lapsed) | Had activity, none for 14 days (less than 45) — 3 days on a self-serve trial, see Trial cadence | lapsed, 1 mail (theme-invite) |
| Dormant | No activity for 45 days — on either track — or an account older than 45 days with no evidence of activity at all (activity records are subject to the tenant's own retention Löschfristen, so a long-ago activity and a purged history read the same) | one final mail, then silence |
Never mailed, regardless of state:
- disabled members (
disabled_at), soft-deleted members, and members under a GDPR Art. 18 processing restriction; - members who opted out (see below);
- members without an e-mail address, or with a test/non-routable address (
.test,.local,.invalid,.example,.localhost); - members of a tenant that is deleted, whose trial has expired, or whose setting resolves to off.
Cadence
The offsets below are not before days from the anchor (the seat's creation for "never started", the last activity for "inactive"). A mail goes out on the next send day after its offset has passed, and never less than 5 days after the previous reactivation mail to the same person (across sequences).
| Sequence | Step | Not before | Content (one call to action each) |
|---|---|---|---|
| never-activated | 1 | day 3 | A minute for a first try? / Eine Minute für einen ersten Versuch? — one small task that works with text only (the tenant's first enabled prompt example, else the built-in friendly payment reminder) and a button that opens the composer with that same text already in place (/easy?text=… — always, the built-in task included; the tenant's example is used whole or not at all — one whose link would not fit the sign-in return path is replaced by the built-in task in both the quote and the link, never cut; nothing is sent automatically) |
| never-activated | 2 | day 7 (effectively day 8 or later, 5-day gap) | Three things colleagues get done with it — write the first draft, turn a long text into a short one, ask instead of searching + one button to open the workspace |
| never-activated | 3 | day 14 | Can we make getting started easier? / Können wir Ihnen den Einstieg leichter machen? — names the colleague who set up the access when known (recorded only when the inviting admin belongs to the same tenant; shown only while that colleague is still an active member and not a platform operator; only a plain personal name is ever used), states the real time since the invitation ("3 weeks ago", never a fixed "two weeks"), and offers one-click reply options (mailto: links to the support mailbox; the subject is the plain option text and the product name — no internal code) |
| lapsed | 1 | day 14 (day 3 on a self-serve trial — see Trial cadence) | There's more you can do — a single positive invitation (replaces the former 14/21/30 drip) that shows 2–3 things the workspace can help with, weighted to the member's broad usage theme inferred locally from their own recent messages (see Theme inference). It never names the theme and never quotes anything specific; the subject is the same for everyone; one button to the workspace. |
| dormant | 1 | day 45 | the "Can we help?" mail once more; when the member already received a reactivation mail before, it carries the line "This is the last e-mail we will send you about this." Nothing follows. |
Trial cadence
A self-serve trial (plan = self_serve_trial) runs only 7 days, so the standard 14-day "inactive"
threshold can never fire before the trial ends: a trial user who tries the product once and then goes
quiet would never be re-engaged. For these tenants the lapsed track is compressed to 3 days (both
the classification threshold and the mail offset) so the single theme-invite can go out inside the
trial window. Everything else is identical to the standard cadence — the never-started mails (day 3 /
7 / 14), the dormant mail (day 45) and the 5-day minimum gap between mails are unchanged, and
other plans (including enterprise POC trials, which run longer) keep the standard 14-day threshold.
Selection is fail-closed: a self_serve_trial whose trial_ends_at is missing or already past uses
the standard cadence. Because mails only go out Tuesday/Thursday mornings, a single trial contains at
most ~2 send windows, so this one touch is best-effort — it reaches a churned trial user when a
send window falls before the trial expires, which the standard cadence never did.
Every mail, once: a short block "What happens when you click? You enter your e-mail address and receive a code by e-mail — no password, about a minute. Everything you type stays inside your company's protected workspace. Nothing can break.", and "Questions? Simply reply to this e-mail." (only while a support mailbox is configured). The copy is written for a reader with no experience of AI systems: one product word (the tenant's product name; otherwise "workspace" / Arbeitsbereich), no technical vocabulary (a unit test rejects Prompt, Modelle, Änderungsprotokoll, Deep-Link, Gateway, Fixture, Changelog in every rendered mail), exactly one button per mail, no pressure in a subject line.
Review the copy before switching on. Myra maintains rendered previews of all six mails in both languages (for the inviter-known, inviter-unknown and final variants — subject, plain text and HTML side by side), kept in step with the live templates. Ask your Myra contact for the current previews before switching the sequence on.
Anyone who becomes active again leaves their sequence immediately; a later lapse starts a fresh one.
Cold start. When the cadence is switched on for an existing workspace, a member whose earlier steps are already past their offsets receives only the current step (missed steps are never replayed), and members who are already dormant receive only the final mail.
Send window. Tuesdays and Thursdays, 09:00–11:59 Europe/Berlin (summer and winter time are handled). The platform has no per-tenant timezone, so Berlin applies to every tenant.
Caps. At most 20 mails per sweep per gateway node (three sweeps fall inside a send
window, so about 60 a day per node; on a multi-site deployment each site runs its own sweep),
and at most reactivation_daily_cap mails per tenant per Berlin calendar day (a
platform setting, default 50) — this cap is enforced in the
database before every send, so it holds across nodes. When more members are due
than the caps allow, "never started" members go first, then "inactive", then "dormant" — and
the newest anchors first within each — with the slots shared round-robin across tenants, so one
large workspace cannot starve the others. The remainder goes out on the next in-window sweep.
Delivery. A mail that could not be handed to the mail relay is retried on the next in-window sweep, at most three times; after the third failure the step is recorded as abandoned and the sequence moves on. Each mail is claimed in the database before it is sent, so two gateway nodes can never send the same step twice; the rare case of a mail that was sent but whose bookkeeping failed twice in a row is re-sent an hour later (bounded by the three-attempt limit — at most two further deliveries in the worst case) and logged as an error.
Every mail carries
- the tenant's product name (white-label branding) and the recipient's name — only when it is a
plain personal name (letters, spaces,
-,',.; up to 64 characters), else a neutral greeting; - the sender: the platform's no-reply address (
From), never a customer address — shown with a human display name (reactivation_sender_name, e.g. "Anna von Myra AI"; unset → the tenant's product name), andReply-To= the support mailbox (support_email, else the built-in customer-success address), so "simply reply to this e-mail" works — a reply that says "no more reminders" is honoured by customer success through the administrative opt-out below. When the configured support mailbox is unusable, the mails promise no reply path and carry no reply options; - the footer, in plain language: "You are receiving this message because your company set up access to … for you. No marketing." / "Sie erhalten diese Nachricht, weil Ihre Firma Ihnen einen Zugang zu … eingerichtet hat. Kein Marketing." — with the opt-out as link text (No more reminders / Keine weiteren Erinnerungen) in HTML and as the bare URL in the plain-text part;
- the headers
List-Unsubscribe(the opt-out URL and, when a support mailbox is configured, amailto:alternative) andAuto-Submitted: auto-generated(so auto-responders stay quiet). RFC 8058 one-click (List-Unsubscribe-Post) is not emitted.
Language
Every lifecycle mail — the sign-in code, the invitation and the reactivation series — is sent in the first of these that is set:
- the member's own interface language (
user.locale, set when the member switches the language in the app); - the workspace's default e-mail language (
tenant.default_locale— User Management → Tenants → (tenant) → Edit → General → Language of e-mails to members, orPATCH /admin/v1/tenants/:id { "default_locale": "de" }); - English.
An invited member has no language of their own until they first switch it, so the workspace default decides what a first-time user reads. It is seeded automatically the first time a colleague from the same workspace invites a member — from that colleague's interface language (the inviting admin's stored language, else the language the admin's browser session was using) — and never overwritten by a later invitation; the tenant admin can change or clear it at any time. A platform operator inviting into a customer workspace never seeds it.
Existing workspaces (set before this rule existed) have no default. Their members receive English mails until the default is set — set it in the tenant editor before switching the reactivation mails on for such a workspace (the release checklist carries this step for the pilot tenants).
Opting out
Every mail links to https://<app>/reactivation/opt-out#t=<signed token>. The token is a signed,
60-day credential naming the member; it travels in the URL fragment, which browsers never send
to a server, so it never appears in access logs. The page shows a confirm button; nothing is
recorded until the member clicks it (a mail scanner pre-fetching the link cannot opt anyone out).
The click calls POST /admin/auth/reactivation/opt-out,
which stamps the member's reactivation_opted_out_at and writes one audit event
(user.reactivation_opted_out). Opting out never changes workspace access.
An administrator can opt a member out (or back in) with
PATCH /admin/v1/users/:id { "reactivation_opted_out": true|false }
— the way to honour an objection received by phone or mail. A member's own link keeps working
after an administrative opt-in: a renewed objection always wins.
Metrics and troubleshooting
- Tenant Analytics → Member reactivation card (tenant admins and platform admins): members
per state (never started / inactive / dormant / active / excluded), mails sent in the last 7 and
30 days, members who came back within 7 days of a mail, opt-outs (total and last 30 days).
API:
GET /admin/v1/tenants/:id/reactivation-metrics. - Platform dashboard (platform admins): the same counters platform-wide plus the ten
most-mailed workspaces of the last 30 days —
GET /admin/v1/stats/reactivation. - "Why did this member (not) get mail X?" —
GET /admin/v1/users/:id/reactivation-statusreturns the exclusion reason, the state and anchor, the next step and when it is due (or why it is blocked), and every mail sent.
Branding and footer of the other service e-mails
The reactivation series above keeps its own plain-language "No marketing" footer with the one-click opt-out. Every other transactional e-mail the workspace sends — the sign-in code, the sign-up code, the invitation, the welcome / order confirmation, the trial-started and trial-converted confirmations, plan-change, payment-failed and auto-top-up-failed notices, the allowance warnings, the cancellation confirmation / code / status mails, the account-deletion (GDPR) warning, the sub-processor-change notice, the scheduled-run-failure and expiring-token notifications, the PII-blocked-delivery notice, and the partner payout mails — now renders on one shared branded template, in the recipient's language:
- a navy branded header carrying the workspace's product name (white-label branding);
- the primary action as a single navy button (log in, manage subscription, update payment, …) whose link resolves to this deployment's own app origin, so a mail sent from int or beta links back to int or beta, never hard-coded to production;
- a product-page link (
www.myra.eu) and the corporate legal footer — Myra Security GmbH, postal address, commercial-register entry, the corporate contact (info@myrasecurity.com,www.myrasecurity.com), and the Legal notice / Privacy policy (Impressum / Datenschutz) links. (The order-confirmation mails additionally link the app Terms (AGB) and Privacy the customer accepted — the contract terms, distinct from the corporate notices.)
Untrusted values are escaped at the boundary (Invariant 11). Every value interpolated into a
mail — the product name, a member's name or e-mail, a token / agent / workflow / schedule name, a
voucher code, and every URL — is HTML-escaped in the HTML part; a value that arrives malformed
or absent falls back to the safe default and is never rendered raw, and every link is
scheme-checked to http(s) (a bad scheme falls back to the app origin). The plain-text part carries
the same content and footer, unescaped, as literal text.
Theme inference
The lapsed mail (above) tailors its 2–3 suggestions to the broad kind of work a member does — writing, research, working with their own documents, coding, summarising/analysis, or everyday communication — so the invitation is relevant rather than generic. It is built to be impossible to embarrass:
- A local classifier reads the member's own recent messages and emits only a coarse 1-of-7 category label. The raw message text is used transiently, in-process, for matching and never leaves the classifier — it is not stored, logged, emailed, or shown. The email that carries the label goes to the member's own mailbox, and its subject is identical for everyone (a lock-screen preview reveals nothing).
- It is fail-closed: the default is the neutral generic invitation, and it upgrades to a theme-shaped one only with clear benign text and no sensitivity signal (health, legal, HR/personnel, personal finance, or personal/relationship content → always the generic mail). Uncertain, thin, metadata-only, or unreadable content also → generic. The mail never names the inferred theme and never quotes anything specific.
- Tenant gate: a tenant that enforces PII masking (
pii_masking_enforced) has its members' content not classified at all — those members receive the generic invitation. - Classification runs locally, in the same trust domain, with no external egress (the platform categorizer model), so no masking/scrub step is required before it.
Legitimate-interest note. Inferring a broad category to shape a service e-mail to a contracted business user is processing under the same legitimate-interest basis as the rest of this feature (the footer says "No marketing"; the opt-out is one click). The balancing rests on the controls above — coarse-label-only output, own-mailbox delivery, invariant subject, the sensitivity veto, the masking-mandate gate, and one-click opt-out — not on the sensitivity screen being exhaustive. Members under an Art. 18 processing restriction are excluded from the cadence entirely (above).
Data protection
- The send log (
user_reactivation_event: who, which step, when, outcome, whether activity followed) is personal data of the member: it is part of the tenant exit export (reactivation_events) and of the member's own Art. 15 export, erased on the right to erasure and on tenant purge, and kept otherwise for the life of the seat (see Conversation retention and deletion). - Only the member's plain name, the inviter's plain name, the tenant's prompt example and a conversation date ever leave the platform by mail — never a conversation title or content.
- Sending is a legitimate-interest service communication to a contracted business user; the footer says so, and the opt-out is one click, without sign-in.
Not in this release
Tenant-admin weekly digest with a one-click "Nudge" / "Remove seat"; tenant-specific "what your colleagues do" content; a per-plan release digest in the "What's new" mail; a monthly opt-in digest after the dormant mail; RFC 8058 one-click unsubscribe.