From b2adaaa30e9385416287b2917cba90196d3c72c2 Mon Sep 17 00:00:00 2001 From: Till JS Date: Fri, 3 Apr 2026 15:01:27 +0200 Subject: [PATCH] refactor(mana-auth): route emails through mana-notify instead of Nodemailer Replace direct Brevo SMTP sending with HTTP calls to mana-notify's notification API. This centralizes all email configuration in one service (mana-notify) and removes the nodemailer dependency from mana-auth. SMTP provider is now swappable via a single env var. Co-Authored-By: Claude Opus 4.6 (1M context) --- docker-compose.macmini.yml | 5 +-- services/mana-auth/package.json | 2 -- services/mana-auth/src/config.ts | 14 ++------ services/mana-auth/src/email/send.ts | 51 +++++++++++++--------------- services/mana-auth/src/index.ts | 2 -- 5 files changed, 26 insertions(+), 48 deletions(-) diff --git a/docker-compose.macmini.yml b/docker-compose.macmini.yml index 9a5e7874d..60a06db1b 100644 --- a/docker-compose.macmini.yml +++ b/docker-compose.macmini.yml @@ -271,10 +271,7 @@ services: MANA_SUBSCRIPTIONS_URL: http://mana-subscriptions:3063 SYNC_DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_platform BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET:-${JWT_SECRET:-your-jwt-secret-change-me}} - SMTP_HOST: smtp-relay.brevo.com - SMTP_PORT: 587 - SMTP_USER: ${SMTP_USER:-94cde5002@smtp-brevo.com} - SMTP_PASS: ${SMTP_PASSWORD} + MANA_NOTIFY_URL: http://mana-notify:3013 SYNAPSE_OIDC_CLIENT_SECRET: ${SYNAPSE_OIDC_CLIENT_SECRET:-} MAX_DAILY_SIGNUPS: ${MAX_DAILY_SIGNUPS:-0} CORS_ORIGINS: https://mana.how,https://calendar.mana.how,https://chat.mana.how,https://clock.mana.how,https://contacts.mana.how,https://context.mana.how,https://docs.mana.how,https://element.mana.how,https://inventar.mana.how,https://link.mana.how,https://cards.mana.how,https://matrix.mana.how,https://mukke.mana.how,https://nutriphi.mana.how,https://photos.mana.how,https://picture.mana.how,https://planta.mana.how,https://playground.mana.how,https://presi.mana.how,https://questions.mana.how,https://skilltree.mana.how,https://storage.mana.how,https://times.mana.how,https://todo.mana.how,https://traces.mana.how,https://zitare.mana.how diff --git a/services/mana-auth/package.json b/services/mana-auth/package.json index 1b6553621..44e786a3c 100644 --- a/services/mana-auth/package.json +++ b/services/mana-auth/package.json @@ -16,12 +16,10 @@ "drizzle-orm": "^0.38.3", "postgres": "^3.4.5", "jose": "^6.1.2", - "nodemailer": "^7.0.12", "bcryptjs": "^3.0.2", "zod": "^3.24.0" }, "devDependencies": { - "@types/nodemailer": "^6.4.17", "@types/bcryptjs": "^2.4.6", "drizzle-kit": "^0.30.4", "typescript": "^5.9.3" diff --git a/services/mana-auth/src/config.ts b/services/mana-auth/src/config.ts index 1be80cc72..c5555d9c9 100644 --- a/services/mana-auth/src/config.ts +++ b/services/mana-auth/src/config.ts @@ -7,12 +7,7 @@ export interface Config { nodeEnv: string; serviceKey: string; cors: { origins: string[] }; - smtp: { - host: string; - port: number; - user: string; - pass: string; - }; + manaNotifyUrl: string; manaCreditsUrl: string; manaSubscriptionsUrl: string; synapseOidcClientSecret: string; @@ -35,12 +30,7 @@ export function loadConfig(): Config { nodeEnv: env('NODE_ENV', 'development'), serviceKey: env('MANA_CORE_SERVICE_KEY', 'dev-service-key'), cors: { origins: env('CORS_ORIGINS', 'http://localhost:5173').split(',') }, - smtp: { - host: env('SMTP_HOST', 'smtp-relay.brevo.com'), - port: parseInt(env('SMTP_PORT', '587'), 10), - user: env('SMTP_USER'), - pass: env('SMTP_PASS'), - }, + manaNotifyUrl: env('MANA_NOTIFY_URL', 'http://localhost:3013'), manaCreditsUrl: env('MANA_CREDITS_URL', 'http://localhost:3061'), manaSubscriptionsUrl: env('MANA_SUBSCRIPTIONS_URL', 'http://localhost:3063'), synapseOidcClientSecret: env('SYNAPSE_OIDC_CLIENT_SECRET'), diff --git a/services/mana-auth/src/email/send.ts b/services/mana-auth/src/email/send.ts index d1c3f8541..668e5e3c4 100644 --- a/services/mana-auth/src/email/send.ts +++ b/services/mana-auth/src/email/send.ts @@ -1,40 +1,35 @@ /** - * Email sending functions using nodemailer. - * German language emails with Brevo SMTP. + * Email sending via mana-notify service. + * All emails are routed through the central notification service + * which handles SMTP, retries, and queuing. */ -import nodemailer from 'nodemailer'; - -let transporter: nodemailer.Transporter | null = null; - -export function initializeEmail(smtp: { host: string; port: number; user: string; pass: string }) { - if (!smtp.host || !smtp.user) { - console.warn('SMTP not configured — emails will be logged to console'); - return; - } - transporter = nodemailer.createTransport({ - host: smtp.host, - port: smtp.port, - secure: false, - auth: { user: smtp.user, pass: smtp.pass }, - }); -} +const NOTIFY_URL = process.env.MANA_NOTIFY_URL || 'http://localhost:3013'; +const SERVICE_KEY = process.env.MANA_CORE_SERVICE_KEY || 'dev-service-key'; async function send(to: string, subject: string, html: string): Promise { - if (!transporter) { - console.log(`[EMAIL] To: ${to} | Subject: ${subject}`); - return true; - } try { - await transporter.sendMail({ - from: '"ManaCore" ', - to, - subject, - html, + const res = await fetch(`${NOTIFY_URL}/api/v1/notifications/send`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Service-Key': SERVICE_KEY, + }, + body: JSON.stringify({ + channel: 'email', + appId: 'mana-auth', + recipient: to, + subject, + body: html, + }), }); + if (!res.ok) { + console.error('mana-notify error:', res.status, await res.text()); + return false; + } return true; } catch (error) { - console.error('Failed to send email:', error); + console.error('Failed to send via mana-notify:', error); return false; } } diff --git a/services/mana-auth/src/index.ts b/services/mana-auth/src/index.ts index d699025bd..e9bbf8cd9 100644 --- a/services/mana-auth/src/index.ts +++ b/services/mana-auth/src/index.ts @@ -13,7 +13,6 @@ import { createBetterAuth } from './auth/better-auth.config'; import { errorHandler } from './middleware/error-handler'; import { jwtAuth } from './middleware/jwt-auth'; import { serviceAuth } from './middleware/service-auth'; -import { initializeEmail } from './email/send'; import { SecurityEventsService, AccountLockoutService } from './services/security'; import { SignupLimitService } from './services/signup-limit'; import { ApiKeysService } from './services/api-keys'; @@ -31,7 +30,6 @@ const db = getDb(config.databaseUrl); const auth = createBetterAuth(config.databaseUrl); // Initialize services -initializeEmail(config.smtp); const security = new SecurityEventsService(db); const lockout = new AccountLockoutService(db); const signupLimit = new SignupLimitService(db);