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.
This commit is contained in:
2025-11-02 02:39:32 +01:00
parent 3b28d1c52d
commit 0dd0ae2bd2
3 changed files with 80 additions and 16 deletions

View File

@@ -75,12 +75,25 @@ Create a .env file and keep it out of version control. Example:
```env ```env
# Email # Email
SMTP_HOST= # For Microsoft 365 / Office 365:
SMTP_HOST=smtp.office365.com
SMTP_PORT=587 SMTP_PORT=587
SMTP_USER= SMTP_USER=your-email@yourdomain.com
SMTP_PASS= SMTP_PASS=your-app-password
ADMIN_EMAIL= # OR use OAuth2 (recommended for Microsoft 365):
WEBSITE_NAME=365DevNet Support # 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 # Monitoring
UPTIME_KUMA_URL= UPTIME_KUMA_URL=

4
src/env.d.ts vendored
View File

@@ -16,6 +16,10 @@ interface ImportMetaEnv {
readonly WEBSITE_NAME?: string; readonly WEBSITE_NAME?: string;
readonly GEMINI_API_KEY?: string; readonly GEMINI_API_KEY?: string;
readonly MANUAL_REVIEW_SECRET?: 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 { interface ImportMeta {

View File

@@ -13,16 +13,25 @@ const {
SMTP_PASS = '', SMTP_PASS = '',
ADMIN_EMAIL = '', ADMIN_EMAIL = '',
WEBSITE_NAME = '365DevNet Support', WEBSITE_NAME = '365DevNet Support',
// Microsoft 365 / OAuth2 (optional)
OAUTH2_CLIENT_ID = '',
OAUTH2_CLIENT_SECRET = '',
OAUTH2_REFRESH_TOKEN = '',
OAUTH2_ACCESS_TOKEN = '',
} = process.env; } = process.env;
// Email configuration // Email configuration
const isProduction = process.env.NODE_ENV === 'production'; 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) // Debug: Log environment variables on load (only in development or if SMTP_HOST is set)
if (!isProduction || SMTP_HOST) { if (!isProduction || SMTP_HOST) {
console.log('[EMAIL CONFIG] SMTP_HOST:', SMTP_HOST || '(not set)'); 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_PORT:', SMTP_PORT || '(using default: 587)');
console.log('[EMAIL CONFIG] SMTP_USER:', SMTP_USER ? '***' : '(not set - no auth)'); 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)'); console.log('[EMAIL CONFIG] ADMIN_EMAIL:', ADMIN_EMAIL || '(not set)');
} }
@@ -41,24 +50,54 @@ function initializeTransporter() {
host: string; host: string;
port: number; port: number;
secure: boolean; secure: boolean;
tls: { rejectUnauthorized: boolean }; tls: { rejectUnauthorized: boolean; ciphers?: string };
auth?: { user: string; pass: string }; auth?: any; // eslint-disable-line @typescript-eslint/no-explicit-any
} = { } = {
host: SMTP_HOST, host: SMTP_HOST,
port: port, port: port,
secure: secure, secure: secure,
tls: { 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 // 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) { if (SMTP_USER && SMTP_PASS) {
transporterConfig.auth = { transporterConfig.auth = {
user: SMTP_USER, user: SMTP_USER,
pass: SMTP_PASS, pass: SMTP_PASS,
}; };
} }
}
transporter = nodemailer.createTransport(transporterConfig); transporter = nodemailer.createTransport(transporterConfig);
@@ -67,12 +106,20 @@ function initializeTransporter() {
console.error('❌ SMTP connection error:', error.message); console.error('❌ SMTP connection error:', error.message);
console.error(' Host:', SMTP_HOST); console.error(' Host:', SMTP_HOST);
console.error(' Port:', port); 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 { } else {
console.log('✅ SMTP server is ready to take messages.'); console.log('✅ SMTP server is ready to take messages.');
console.log(' Host:', SMTP_HOST); console.log(' Host:', SMTP_HOST);
console.log(' Port:', port); 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 { } else {