Email system
Verified 2026-09-10 · Brevo + Gmail · all transactional flows
One overview of every email a byForja contact may receive. Who triggers it. What template it uses. Where the code lives. Read back on 2026-09-10 from byforja-site and byforja-backup-worker.
Brevo handles every transactional email the site sends (sender Forja <contact@byforja.com>, helper functions/api/_lib/brevo.js, free plan 300/day, EU region). Gmail (al@byforja.com) carries the outreach sequence. No newsletter tool is wired.
Transactional emails (Brevo + Gmail)
| Trigger | Template file | Endpoint | First-email footer? | Status | |
|---|---|---|---|---|---|
| User requests a sign-in link (FR page) | Magic link · "Connexion à Forja" | _lib/brevo.js via auth/magic-link.js | /api/auth/magic-link | None (sign-in mail) | live |
| User requests a sign-in link (EN page) | Magic link · "Sign in to Forja" | _lib/brevo.js via auth/magic-link.js | /api/auth/magic-link | None (sign-in mail) | live |
| Client validates a brand swipe | Client mail · "Your brand is validated" · from Forja <al@byforja.com> | account/brand-swipe-validate.js | /api/account/brand-swipe-validate | None | live |
| Client validates a brand swipe | Admin notice · "[byForja] {first name} validated their brand swipe" · to alexandre.corne.ac@gmail.com | account/brand-swipe-validate.js | /api/account/brand-swipe-validate | None | live |
| Outreach first touch (Loom email), sent by AL from Gmail | T1 · tracked by pixel /i/{token} + links /l/… (tables email_sends / email_opens / email_clicks / email_links) | byforja-site functions/i/[token].js, functions/l/[[path]].js | /i/{token} · /l/* | None | live since 04/09/2026 |
| Follow-up due (T2 +3d, T4 +12d, T5 +18d after Date Loom), CRON9 five times an hour | Gmail reply in the prospect thread from al@byforja.com · T2/T4 text from the Notion "Next touch draft" column, T5 fixed text | byforja-backup-worker/src/gmail-followup.js | worker cron · POST /admin/gmail-followup-now | None | live · LIVE_SEND gate |
Newsletter broadcasts
No newsletter tool is wired on byForja (no Kit, no Brevo campaign). The newsletter_signup event type is accepted by /api/events but no form on byforja.com sends it (read back 2026-09-10).
| Setting | Where | Status |
|---|---|---|
| Newsletter tool | — | none wired |
First-email footer helper
No first-email footer helper on byForja: the Brevo mails above are sign-in and account notices, not marketing, and the outreach sequence stops on reply or booking rather than on an unsubscribe link.
Files
- Brevo helper: byforja-site/functions/api/_lib/brevo.js
- Outreach tracking tables: byforja-site/migrations/0031_email_tracking.sql
- Follow-up robot: byforja-backup-worker/src/gmail-followup.js (CRON9 on /crons)
Functions exposed
| Function | Purpose | Used by |
|---|---|---|
| sendEmail | Brevo transactional send; returns skipped_no_config when BREVO_API_KEY is absent so callers still answer 200. | Magic link, brand swipe validation |
| sendMinuteFor | Per-prospect send minute so no follow-up lands on the hour. | gmail-followup.js |
Unsubscribe
No unsubscribe route on byForja: no marketing email is sent. The outreach sequence has its own stop rule.
- Stop rule: CRON9 dual check before every send, a Cal.com booking under the prospect email OR a last message in the Gmail thread coming from the prospect. Either one ends the sequence and updates the Notion status.
- T3 is never sent by the robot (second raw Loom, manual).
- Confirmation page: none (no unsubscribe flow).
Edit a copy
- Open the template string inside byforja-site/functions/api/auth/magic-link.js (FR and EN blocks) or functions/api/account/brand-swipe-validate.js.
- Edit the readable strings inside the HTML literal.
- Deploy site: cd ~/Projects/byforja-site && npm run deploy:prod (preview first with deploy:preview).
- Smoke: request a sign-in link on prod and inspect the resulting email. T2/T4 copy lives in Notion, not in code.
Open items
- to verify Brevo domain authentication (DKIM CNAMEs brevo1/brevo2._domainkey + brevo-code TXT) required by _lib/brevo.js: status not read back on 2026-09-10, check the Brevo dashboard.
- todo No newsletter path: the newsletter_signup event exists, nothing sends it.
- to verify Outreach opens counted with proxied = 1 (Gmail / Apple image proxies) are not human reads: keep them apart in any open rate.