From 0dd0ae2bd2692855d0deae1e7ab78eb4a9ef394a Mon Sep 17 00:00:00 2001 From: Richard Bergsma Date: Sun, 2 Nov 2025 02:39:32 +0100 Subject: [PATCH] Update email configuration in README and enhance email handler for Microsoft 365 support - Updated the README.md to include specific SMTP settings for Microsoft 365 and OAuth2 authentication options. - Modified the email handler to support OAuth2 authentication for Microsoft 365, improving security and flexibility. - Enhanced logging to provide clearer feedback on email configuration and authentication methods used. --- README.md | 23 ++++++++++--- src/env.d.ts | 4 +++ src/utils/email-handler.ts | 69 ++++++++++++++++++++++++++++++++------ 3 files changed, 80 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index b823731..8d56979 100644 --- a/README.md +++ b/README.md @@ -75,12 +75,25 @@ Create a .env file and keep it out of version control. Example: ```env # Email -SMTP_HOST= +# For Microsoft 365 / Office 365: +SMTP_HOST=smtp.office365.com SMTP_PORT=587 -SMTP_USER= -SMTP_PASS= -ADMIN_EMAIL= -WEBSITE_NAME=365DevNet Support +SMTP_USER=your-email@yourdomain.com +SMTP_PASS=your-app-password +# OR use OAuth2 (recommended for Microsoft 365): +# OAUTH2_CLIENT_ID=your-client-id +# OAUTH2_CLIENT_SECRET=your-client-secret +# OAUTH2_REFRESH_TOKEN=your-refresh-token +# OAUTH2_ACCESS_TOKEN=your-access-token (optional) + +# For generic SMTP or Mailcow: +# SMTP_HOST=your-smtp-server +# SMTP_PORT=587 +# SMTP_USER=your-username +# SMTP_PASS=your-password + +ADMIN_EMAIL=your-email@yourdomain.com +WEBSITE_NAME= # Monitoring UPTIME_KUMA_URL= diff --git a/src/env.d.ts b/src/env.d.ts index b6fd8a1..22391c8 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -16,6 +16,10 @@ interface ImportMetaEnv { readonly WEBSITE_NAME?: string; readonly GEMINI_API_KEY?: string; readonly MANUAL_REVIEW_SECRET?: string; + readonly OAUTH2_CLIENT_ID?: string; + readonly OAUTH2_CLIENT_SECRET?: string; + readonly OAUTH2_REFRESH_TOKEN?: string; + readonly OAUTH2_ACCESS_TOKEN?: string; } interface ImportMeta { diff --git a/src/utils/email-handler.ts b/src/utils/email-handler.ts index e57f309..a597c16 100644 --- a/src/utils/email-handler.ts +++ b/src/utils/email-handler.ts @@ -13,16 +13,25 @@ const { SMTP_PASS = '', ADMIN_EMAIL = '', WEBSITE_NAME = '365DevNet Support', + // Microsoft 365 / OAuth2 (optional) + OAUTH2_CLIENT_ID = '', + OAUTH2_CLIENT_SECRET = '', + OAUTH2_REFRESH_TOKEN = '', + OAUTH2_ACCESS_TOKEN = '', } = process.env; // Email configuration const isProduction = process.env.NODE_ENV === 'production'; +// Check if using Microsoft 365 +const isMicrosoft365 = SMTP_HOST.includes('office365.com') || SMTP_HOST.includes('outlook.com'); + // Debug: Log environment variables on load (only in development or if SMTP_HOST is set) if (!isProduction || SMTP_HOST) { console.log('[EMAIL CONFIG] SMTP_HOST:', SMTP_HOST || '(not set)'); console.log('[EMAIL CONFIG] SMTP_PORT:', SMTP_PORT || '(using default: 587)'); console.log('[EMAIL CONFIG] SMTP_USER:', SMTP_USER ? '***' : '(not set - no auth)'); + console.log('[EMAIL CONFIG] Provider:', isMicrosoft365 ? 'Microsoft 365' : 'Generic SMTP'); console.log('[EMAIL CONFIG] ADMIN_EMAIL:', ADMIN_EMAIL || '(not set)'); } @@ -41,23 +50,53 @@ function initializeTransporter() { host: string; port: number; secure: boolean; - tls: { rejectUnauthorized: boolean }; - auth?: { user: string; pass: string }; + tls: { rejectUnauthorized: boolean; ciphers?: string }; + auth?: any; // eslint-disable-line @typescript-eslint/no-explicit-any } = { host: SMTP_HOST, port: port, secure: secure, tls: { - rejectUnauthorized: false, // Accept self-signed certificates (useful for Mailcow) + rejectUnauthorized: isMicrosoft365 ? true : false, // Microsoft 365 requires valid certificates + // Microsoft 365 specific TLS configuration + ...(isMicrosoft365 && { + ciphers: 'SSLv3', + }), }, }; - // Add authentication if credentials are provided - if (SMTP_USER && SMTP_PASS) { - transporterConfig.auth = { - user: SMTP_USER, - pass: SMTP_PASS, - }; + // Microsoft 365 requires authentication - use OAuth2 if available, otherwise basic auth + if (isMicrosoft365) { + if (OAUTH2_CLIENT_ID && OAUTH2_CLIENT_SECRET && OAUTH2_REFRESH_TOKEN) { + // OAuth2 authentication for Microsoft 365 + transporterConfig.auth = { + type: 'OAuth2', + user: SMTP_USER || ADMIN_EMAIL, + clientId: OAUTH2_CLIENT_ID, + clientSecret: OAUTH2_CLIENT_SECRET, + refreshToken: OAUTH2_REFRESH_TOKEN, + ...(OAUTH2_ACCESS_TOKEN && { accessToken: OAUTH2_ACCESS_TOKEN }), + }; + console.log('[EMAIL CONFIG] Using OAuth2 authentication for Microsoft 365'); + } else if (SMTP_USER && SMTP_PASS) { + // Basic authentication for Microsoft 365 (email + password or app password) + transporterConfig.auth = { + user: SMTP_USER, + pass: SMTP_PASS, + }; + console.log('[EMAIL CONFIG] Using basic authentication for Microsoft 365'); + console.log('[EMAIL CONFIG] Note: For better security, consider using OAuth2 with app-specific password'); + } else { + console.warn('[EMAIL CONFIG] ⚠️ Microsoft 365 requires authentication but no credentials provided'); + } + } else { + // Generic SMTP - add authentication if credentials are provided + if (SMTP_USER && SMTP_PASS) { + transporterConfig.auth = { + user: SMTP_USER, + pass: SMTP_PASS, + }; + } } transporter = nodemailer.createTransport(transporterConfig); @@ -67,12 +106,20 @@ function initializeTransporter() { console.error('❌ SMTP connection error:', error.message); console.error(' Host:', SMTP_HOST); console.error(' Port:', port); - console.error(' Auth:', SMTP_USER ? 'Yes' : 'No'); + console.error(' Provider:', isMicrosoft365 ? 'Microsoft 365' : 'Generic SMTP'); + console.error(' Auth:', (transporterConfig.auth ? 'Yes' : 'No')); + if (isMicrosoft365 && error.message.includes('authentication')) { + console.error(' 💡 Tip: For Microsoft 365, ensure:'); + console.error(' - Using your full email address as SMTP_USER'); + console.error(' - Using an app-specific password (not your regular password)'); + console.error(' - Or configure OAuth2 with OAUTH2_CLIENT_ID, OAUTH2_CLIENT_SECRET, and OAUTH2_REFRESH_TOKEN'); + } } else { console.log('✅ SMTP server is ready to take messages.'); console.log(' Host:', SMTP_HOST); console.log(' Port:', port); - console.log(' Auth:', SMTP_USER ? 'Yes' : 'No'); + console.log(' Provider:', isMicrosoft365 ? 'Microsoft 365' : 'Generic SMTP'); + console.log(' Auth:', (transporterConfig.auth ? 'Yes' : 'No')); } }); } else {