Relay transactional email through Salesforce instead of SMTP

Our SMTP host's IP reputation gets its mail blocked by allowlist-based
receivers (t-online.de). Route voucher confirmations, account activation
and password-reset mail through the Salesforce org's MTA + DKIM instead,
via a new EmailSendResource Apex REST endpoint.

- common/salesforce.client.ts: shared client-credentials access (token
  cache + retry-once-on-401), extracted from the newsletter sync so it is
  no longer duplicated
- common.mail.nodemailer.ts -> common.mail.ts: posts to the org endpoint,
  never throws on a delivery failure (logs + returns a boolean), retries
  once on a transient failure, base64-encodes attachments with a 3 MB cap
- drop the nodemailer dependency
- fixes activation/reset email failures that previously threw after the
  transaction had already committed
- tickets.confirmation-email.ts: shared confirmation-email builder used by
  both the public redeem path and a new admin resend action
- redemptions gain a confirmation_email_status column (migration 003) so
  the admin UI can flag a failed send; POST
  /tickets/admin/redemptions/:id/resend-confirmation rebuilds and resends

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-30 15:50:47 +02:00
parent 3c4f3331d8
commit 69904b749c
15 changed files with 690 additions and 141 deletions
@@ -0,0 +1,7 @@
-- Nachklang e.V. Tickets module — records the outcome of the redemption
-- confirmation email on the redemption itself, so the admin UI can flag a
-- failed send and offer a resend. NULL until the post-commit send resolves.
-- Apply manually against TICKETS_DB, after 002_add_require_address.sql:
-- mysql -h <DB_HOST> -u <DB_USER> -p <TICKETS_DB> < 003_add_confirmation_email_status.sql
ALTER TABLE redemptions
ADD COLUMN confirmation_email_status ENUM('SENT','FAILED') NULL DEFAULT NULL AFTER redeemed_at;