feat: implement email sending functionality with SMTP and Resend fallback
CI / skip-ci-check (pull_request) Successful in 29s
CI / lint-and-type-check (pull_request) Has been cancelled
CI / python-lint (pull_request) Has been cancelled
CI / test-backend (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
CI / secret-scanning (pull_request) Has been cancelled
CI / dependency-scan (pull_request) Has been cancelled
CI / sast-scan (pull_request) Has been cancelled
CI / workflow-summary (pull_request) Has been cancelled
CI / skip-ci-check (pull_request) Successful in 29s
CI / lint-and-type-check (pull_request) Has been cancelled
CI / python-lint (pull_request) Has been cancelled
CI / test-backend (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
CI / secret-scanning (pull_request) Has been cancelled
CI / dependency-scan (pull_request) Has been cancelled
CI / sast-scan (pull_request) Has been cancelled
CI / workflow-summary (pull_request) Has been cancelled
- Added support for sending emails using SMTP configuration or Resend API as a fallback. - Updated environment variables in .env_example for SMTP settings. - Enhanced email confirmation process with improved error handling and fallback logic. - Introduced a test script to validate email sending configuration and functionality.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { Resend } from 'resend';
|
||||
import nodemailer from 'nodemailer';
|
||||
import * as dotenv from 'dotenv';
|
||||
|
||||
// Load environment variables
|
||||
@@ -6,63 +7,96 @@ dotenv.config();
|
||||
|
||||
const resend = new Resend(process.env.RESEND_API_KEY);
|
||||
|
||||
function smtpEnabled(): boolean {
|
||||
return Boolean(
|
||||
process.env.SMTP_HOST &&
|
||||
process.env.SMTP_USER &&
|
||||
process.env.SMTP_PASS
|
||||
);
|
||||
}
|
||||
|
||||
async function testEmailSending() {
|
||||
console.log('🧪 Testing email sending configuration...\n');
|
||||
|
||||
// Check environment variables
|
||||
console.log('📋 Environment Variables:');
|
||||
console.log(' EMAIL_PROVIDER:', process.env.EMAIL_PROVIDER || 'smtp (default)');
|
||||
console.log(' SMTP_HOST:', process.env.SMTP_HOST || '❌ NOT SET');
|
||||
console.log(' SMTP_PORT:', process.env.SMTP_PORT || '465 (default)');
|
||||
console.log(' SMTP_SECURE:', process.env.SMTP_SECURE || 'true (default)');
|
||||
console.log(' SMTP_USER:', process.env.SMTP_USER || '❌ NOT SET');
|
||||
console.log(' SMTP_FROM_EMAIL:', process.env.SMTP_FROM_EMAIL || '❌ NOT SET');
|
||||
console.log(' RESEND_API_KEY:', process.env.RESEND_API_KEY ? `${process.env.RESEND_API_KEY.substring(0, 10)}...` : '❌ NOT SET');
|
||||
console.log(' RESEND_FROM_EMAIL:', process.env.RESEND_FROM_EMAIL || '❌ NOT SET');
|
||||
console.log(' NEXTAUTH_URL:', process.env.NEXTAUTH_URL || '❌ NOT SET');
|
||||
console.log('');
|
||||
|
||||
if (!process.env.RESEND_API_KEY) {
|
||||
console.error('❌ RESEND_API_KEY is not set in .env file');
|
||||
|
||||
const toEmail = process.env.TEST_EMAIL_TO || process.env.SMTP_USER || process.env.RESEND_FROM_EMAIL;
|
||||
if (!toEmail) {
|
||||
console.error('❌ Set TEST_EMAIL_TO or SMTP_USER in .env to run this test.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!process.env.RESEND_FROM_EMAIL) {
|
||||
console.error('❌ RESEND_FROM_EMAIL is not set in .env file');
|
||||
|
||||
if (smtpEnabled()) {
|
||||
console.log('📤 Attempting SMTP test first...');
|
||||
try {
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: process.env.SMTP_HOST,
|
||||
port: Number(process.env.SMTP_PORT || 465),
|
||||
secure: (process.env.SMTP_SECURE || 'true').toLowerCase() === 'true',
|
||||
auth: {
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PASS,
|
||||
},
|
||||
});
|
||||
|
||||
const smtpFromEmail = process.env.SMTP_FROM_EMAIL || process.env.SMTP_USER!;
|
||||
const smtpFromName = process.env.SMTP_FROM_NAME;
|
||||
const smtpReplyTo = process.env.SMTP_REPLY_TO || smtpFromEmail;
|
||||
const smtpFrom = smtpFromName
|
||||
? `${smtpFromName} <${smtpFromEmail}>`
|
||||
: smtpFromEmail;
|
||||
|
||||
const info = await transporter.sendMail({
|
||||
from: smtpFrom,
|
||||
to: toEmail,
|
||||
replyTo: smtpReplyTo,
|
||||
subject: 'SMTP test from PunimTag',
|
||||
text: 'SMTP test email from PunimTag viewer frontend.',
|
||||
});
|
||||
|
||||
console.log('✅ SMTP test sent successfully');
|
||||
console.log(' Message ID:', info.messageId);
|
||||
process.exit(0);
|
||||
} catch (smtpError: any) {
|
||||
console.error('⚠️ SMTP test failed, will try Resend fallback.');
|
||||
console.error(' SMTP error:', smtpError.message);
|
||||
}
|
||||
} else {
|
||||
console.log('ℹ️ SMTP config not set, skipping SMTP test.');
|
||||
}
|
||||
|
||||
if (!process.env.RESEND_API_KEY || !process.env.RESEND_FROM_EMAIL) {
|
||||
console.error('❌ Resend fallback not configured (RESEND_API_KEY/RESEND_FROM_EMAIL missing).');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Clean up the from email (remove quotes and spaces)
|
||||
const fromEmail = process.env.RESEND_FROM_EMAIL.trim().replace(/^["']|["']$/g, '');
|
||||
console.log('📧 Using FROM email:', fromEmail);
|
||||
console.log('');
|
||||
|
||||
// Test email sending
|
||||
console.log('📤 Attempting to send test email...');
|
||||
|
||||
const resendFrom = process.env.RESEND_FROM_EMAIL.trim().replace(/^["']|["']$/g, '');
|
||||
console.log('📤 Attempting Resend fallback test...');
|
||||
try {
|
||||
const result = await resend.emails.send({
|
||||
from: fromEmail,
|
||||
to: 'test@example.com', // This will fail but we'll see the error
|
||||
subject: 'Test Email',
|
||||
html: '<p>This is a test email</p>',
|
||||
from: resendFrom,
|
||||
to: toEmail,
|
||||
subject: 'Resend fallback test from PunimTag',
|
||||
html: '<p>Resend fallback test email from PunimTag viewer frontend.</p>',
|
||||
});
|
||||
|
||||
console.log('✅ Email API call successful!');
|
||||
console.log('Response:', JSON.stringify(result, null, 2));
|
||||
if (result.error) {
|
||||
throw new Error(result.error.message || 'Unknown Resend API error');
|
||||
}
|
||||
console.log('✅ Resend fallback test sent successfully');
|
||||
console.log(' Email ID:', result.data?.id);
|
||||
} catch (error: any) {
|
||||
console.error('❌ Error sending email:');
|
||||
console.error(' Message:', error.message);
|
||||
if (error.response) {
|
||||
console.error(' Response:', JSON.stringify(error.response, null, 2));
|
||||
}
|
||||
|
||||
// Check for common errors
|
||||
if (error.message?.includes('domain')) {
|
||||
console.error('\n⚠️ Domain verification issue:');
|
||||
console.error(' The email domain needs to be verified in Resend dashboard');
|
||||
console.error(' For testing, use: onboarding@resend.dev');
|
||||
}
|
||||
|
||||
if (error.message?.includes('unauthorized') || error.message?.includes('Invalid API key')) {
|
||||
console.error('\n⚠️ API Key issue:');
|
||||
console.error(' Check that your RESEND_API_KEY is correct');
|
||||
console.error(' Get a new key from: https://resend.com/api-keys');
|
||||
}
|
||||
|
||||
console.error('❌ Resend fallback failed:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user