Notifications & email events
Every significant event on the platform produces an in-app notification (the bell in the menubar) and, in most cases, a matching email. This page is the reference for what fires when, who receives it, and the controls operators have over delivery.
The settings page (Platform → Notifications)​
Four sub-tabs:
- Delivery: whether email is on, the sender name, the backend in use, and Send test.
- Service emails: Who is told, the addresses that get each kind of notice the platform team receives (see below).
- Templates: the saved templates as rows (New template starts from a preset: Minimal, Announcement or Blank). Edit opens the template in a dialog: the subject, the HTML body with its toolbar, the plain-text body on its own tab, the variables to copy, and a live preview with sample values, desktop or phone. Make default names the template every email uses and is saved at once. The default, a template an event uses, and the last template cannot be deleted.
- Rules: the template every email uses unless an event's row names another, then every event grouped (account and security, organisations and members, projects and review, money, platform) with two columns, Email (a toggle) and Template. Each change is saved at once. In-app notices are always sent.
Three variables carry the organisation an email is from, when it is
from one: organization_name, organization_line ("From Hausa Lab on
AfriAnnotate"; the bundled template and the presets show it under the
header) and organization_contact (the organisation's contact address,
shown in the footer). Each is empty for an email that is not about an
organisation, so a template may name them without a check.
Each sub-tab has its own address (#delivery, #service, #templates,
#rules), so a refresh or a shared link lands on the same one.
How delivery works​
-
The in-app bell entry is always created.
-
The email is sent only if Platform → Notifications allows it: a master email switch plus per-kind rules (
kind_email_rules). A kind with no explicit rule defaults to allowed. -
Each user then applies their own email volume profile (Profile → Preferences → Email volume):
Profile What emails Everything (default) Every notification the platform rules allow Essential Skips chatty emails — project resumed/paused, review assignments, inactivity nudges. Membership, review outcomes, governance, money and security still email Critical only Security alerts, account changes, consent receipts, payout emails — plus the membership/org events you can't afford to miss: password reset, email verification, invite, welcome, device-linked receipt, org deleted (owner + members), member removed / suspended, auto-suspend warning The profile filters email only — suppressed events remain in the bell, and security/consent/payout receipts email on every profile.
-
Users with a digest preference receive unread notifications batched daily/weekly instead of per-event (see
send_notification_digests). -
A failed email send is recorded in Platform → Audit log as
email.send_failed— a silently broken SMTP config is no longer invisible.
Account & security — sent to the account owner​
| Event | Notes |
|---|---|
| Signup email verification | Link must be clicked before first login |
| Password reset requested | |
| Password changed | "If this wasn't you…" alert |
| Passkey added / removed | Points to Profile → Security |
| Account deactivated / reactivated | By a platform admin |
| Platform-admin access granted / revoked | |
| Hugging Face token saved | Credential-change alert |
| Account deleted | Farewell + data-deletion confirmation, sent before the account is removed |
| Email-change requested | Courtesy warning to the old address; verify link to the new one |
| Desktop device linked to cloud | Consent receipt for what is stored |
Who is told​
Platform → Notifications → Service emails (the card Who is told) lists every kind of notice
the platform team gets (quota requests, feedback, support access
requests, and whatever an installed extension adds) with the addresses
that receive its email, comma-separated: billing@… for one kind,
security@… for another. A kind with no addresses falls back to the
community inbox below, and that to each staff account. Staff always get
the in-app notice. A row may also name a prefix (security) to cover
every kind under it.
Community inbox​
Anything the community sends the platform team — quota requests, in-app feedback, and future platform-directed notices — is emailed once to the address set under Platform → Settings → Policies → Community inbox, instead of to every staff account. Staff still get their in-app bell rows. Leave it empty and each staff account is emailed individually.
The intended address is a Google Group so the whole team is notified and the membership is managed in one place:
- At groups.google.com create a group
(for example
afriannotate-team), type Email list. - Under Group settings → Posting policies set Who can post to Anyone on the web, so the platform's sending address is accepted (or add that address as a member). Turn off moderation for non-members if the group is otherwise closed, or messages will wait in the moderation queue.
- Under Member settings make sure everyone's Subscription is Each email (not digest) if they want to see requests as they arrive.
- Paste the group address into Community inbox and save. Send a test from Platform → Notifications → Send test email to the same address to confirm delivery.
Per-event email rules (below) still apply: turning off
platform.quota_request there silences the inbox email for it too.
Organizations​
| Event | Recipient |
|---|---|
| Org created / tier provisioned | Org owner (welcome + quota summary) |
| Org deleted | Owner (personal note) + every remaining member |
| Member added / invited | The member |
| Member removed (org settings or platform admin) | The member |
| Member role changed | The member |
| Member suspended / unsuspended (manual or auto-suspend) | The member |
| Auto-suspend grace warning | The at-risk member |
| Auto-suspend rule created / updated / deleted | Org owner |
| Quotas changed by platform admin (members, projects, tasks, storage per project) | Org owner |
| Quota 80% / 100% reached | Org owners |
Quota increase requested by an org owner / admin (platform.quota_request) | Every platform staff account in-app; one email to the community inbox (or each staff account when none is set), linking to the review modal |
Quota request decided (org.quota_request_decided) | Org owners and admins, one line per item: approved with the new limit, declined with the reason, or still under review |
An organisation lets support in (platform.support_access) | Every platform staff account in-app, with the organisation's reason |
New in-app feedback (platform.feedback) | Community inbox by email only (no bell) |
| Ownership transferred | New owner and outgoing owner |
Projects & review​
| Event | Recipient |
|---|---|
| Project published / paused / resumed | Annotators, reviewers, guests on the project |
| Project deleted | All project members except the deleter |
| Project member added / paused / resumed / removed / role changed | The member |
| Reviewers assigned tasks | The reviewers |
| Re-review requested (rejection dispute) | The reviewer who rejected |
| Work reviewed (rollup: N accepted, M rejected) | The annotator — sent when the reviewer's queue drains, on bulk accept-all, and swept hourly-stale by the digest job so a rejection never sits unannounced |
| Annotator auto-paused on quality | The annotator + project admins |
| Annotator inactivity reminder | The idle annotator |
| Data-retention purge warning / execution | Project creator + org owners |
Consent​
| Event | Recipient |
|---|---|
| Signature receipt | The signer — template, version, project; their durable proof |
| Consent withdrawn | The user (record of withdrawal) and the org owner (duty to stop processing) |
| New consent required on a project | Every project member, before the gate surprises them |
Money​
| Event | Recipient |
|---|---|
| Rate card changed | All contributors on the project |
| Contributor declines new rates | Project owner |
| Payout run created | Every contributor in the run — units + amount queued |
| Payout run marked paid | Every contributor — amount, reference, pointer to their receipt |
| Draft payout run deleted | Every contributor — entries returned to the unpaid pool |
Operational alerts — capped at one per day per source​
| Event | Recipient |
|---|---|
| Cloud-storage sync failure (incl. stalled jobs) | Project creator + org owner |
| Webhook delivery failure (HTTP ≥ 400 or connection error) | Org owner |
| ML backend healthy → broken, or training failure | Project creator |
Exports and bulk imports run synchronously on the reference deployment — the requester sees success or failure directly in the response, so no email is sent for them.