AcadeDoc/apps/server/src/integrations/transactional
Corentin b53ab5043f feat(acadedoc): add AcadeDoc branding, Brevo SMTP preset, UI customization — R4.4
- Rebranding: BRAND_NAME env var (default AcadeDoc) replaces hardcoded "DocAdenice"
  in index.html title/meta, PWA manifest, app-header logo text, email footer/body
- lib/config.ts: getAppName() reads BRAND_NAME; new getBrandLogoUrl/PrimaryColor/AccentColor helpers
- vite.config.ts: BRAND_* vars exposed via define block to client
- brand-theme.ts: getBrandTheme() generates 10-shade MantineColorsTuple from hex
  (no @mantine/colors-generator dep); merged into MantineProvider at boot
- theme/__tests__/brand-theme.test.ts: 11 vitest tests (generateColorTuple + getBrandTheme)
- Workspace branding: migration adds primary_color/accent_color to workspaces table
  WorkspaceBrandingService + WorkspaceBrandingController (POST /workspace/branding,
  POST /workspace/branding/update — admin only) + DTO hex validation
- Settings: /settings/branding page (WorkspaceBranding) + sidebar entry (admin-only)
- workspace-branding.spec.ts: 13 vitest tests (service + controller + DTO validation)
- SMTP Brevo: .env.example preset block + transactional/README.md ops guide
  (key gen, port 587 STARTTLS, 300/day free limit, swaks/curl test)
- environment.service.ts: getMailFromName() falls back to BRAND_NAME if MAIL_FROM_NAME unset
- vitest.config.ts server: include pattern extended to src/core/workspace/spec/**
- i18n: 11 branding keys added to en-US and fr-FR translations
- 0 TypeScript errors client + server, 11 client + 13 server new tests all green

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 11:36:38 +02:00
..
css implement new invitation system 2024-05-14 22:55:11 +01:00
emails feat(acadedoc): add AcadeDoc branding, Brevo SMTP preset, UI customization — R4.4 2026-05-08 11:36:38 +02:00
partials feat(acadedoc): add AcadeDoc branding, Brevo SMTP preset, UI customization — R4.4 2026-05-08 11:36:38 +02:00
utils feat(backend): forgot password (#250) 2024-09-17 15:52:47 +01:00
README.md feat(acadedoc): add AcadeDoc branding, Brevo SMTP preset, UI customization — R4.4 2026-05-08 11:36:38 +02:00

Transactional Mail — AcadeDoc

Architecture

AcadeDoc uses NestJS + nodemailer for transactional email. Emails are rendered with react-email and enqueued via BullMQ. The driver is selected at boot time from MAIL_DRIVER (smtp | postmark | log).

All email templates live in emails/. Partials (header, footer, button) are in partials/. CSS helpers are in css/.


Configuring Brevo (SMTP relay)

Brevo (ex-Sendinblue) is the recommended SMTP relay for AcadeDoc selfhost.

1. Create a Brevo account

Go to https://app.brevo.com and register.

2. Generate an SMTP key

  1. Log in to Brevo dashboard.
  2. Navigate to Settings > SMTP & API > SMTP.
  3. Click Generate a new SMTP key.
  4. Copy the key — it is shown only once. This key is your SMTP_PASSWORD. It is NOT your account password.

3. Set the environment variables

MAIL_DRIVER=smtp
SMTP_HOST=smtp-relay.brevo.com
SMTP_PORT=587
SMTP_USERNAME=<your-brevo-login-email>
SMTP_PASSWORD=<smtp-master-key-from-step-2>
SMTP_SECURE=false
SMTP_IGNORETLS=false

MAIL_FROM_ADDRESS=noreply@yourdomain.com
MAIL_FROM_NAME=AcadeDoc

SMTP_SECURE=false + SMTP_IGNORETLS=false instructs nodemailer to upgrade the connection to TLS via STARTTLS on port 587. This is the correct mode for Brevo (port 587 is STARTTLS, port 465 is implicit TLS / SMTP_SECURE=true).

4. Brevo free plan limits

Metric Free plan
Emails/day 300
Emails/month 9 000
Contacts Unlimited
SMTP relay Yes

For internal team usage (< 50 members), 300 emails/day is more than enough. Upgrade if you need more capacity.

5. Test from the server

After deploying, send a test from the container/server shell:

# Using swaks (SMTP Swiss Army Knife)
swaks \
  --to test@example.com \
  --from noreply@yourdomain.com \
  --server smtp-relay.brevo.com:587 \
  --auth LOGIN \
  --auth-user "<your-brevo-login-email>" \
  --auth-password "<smtp-key>" \
  --tls \
  --header "Subject: AcadeDoc SMTP test"

Or via curl (base64-encode credentials):

curl --url "smtp://smtp-relay.brevo.com:587" \
  --ssl-reqd \
  --mail-from "noreply@yourdomain.com" \
  --mail-rcpt "test@example.com" \
  --user "<login>:<smtp-key>" \
  -T - <<EOF
From: noreply@yourdomain.com
To: test@example.com
Subject: AcadeDoc SMTP test

Test email from AcadeDoc.
EOF

If swaks/curl are not available in the container, trigger a password-reset from the AcadeDoc UI with a real user email and check delivery.


STARTTLS vs TLS notes

Env variable Value Effect
SMTP_SECURE false Port 587 / STARTTLS (recommended)
SMTP_SECURE true Port 465 / implicit TLS
SMTP_IGNORETLS false Allow STARTTLS upgrade (default)
SMTP_IGNORETLS true Disable TLS entirely (insecure, dev only)

Brevo port 587 requires STARTTLS. Do not set SMTP_SECURE=true on port 587.