feat: replace Resend SDK with Mailcow SMTP (nodemailer)
Swap email sending from Resend API to self-hosted Mailcow at mx.jeffemmett.com. Uses SMTP_PASS env var instead of RESEND_API_KEY. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c32070806a
commit
c3e67b9cae
|
|
@ -19,8 +19,8 @@
|
|||
"dependencies": {
|
||||
"express": "^4.18.2",
|
||||
"googleapis": "^144.0.0",
|
||||
"pg": "^8.11.3",
|
||||
"resend": "^4.0.0"
|
||||
"nodemailer": "^6.9.0",
|
||||
"pg": "^8.11.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
|
|
|
|||
24
server.js
24
server.js
|
|
@ -2,7 +2,7 @@ const express = require('express');
|
|||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
const { google } = require('googleapis');
|
||||
const { Resend } = require('resend');
|
||||
const nodemailer = require('nodemailer');
|
||||
const { Pool } = require('pg');
|
||||
|
||||
const app = express();
|
||||
|
|
@ -10,8 +10,16 @@ const PORT = process.env.PORT || 3000;
|
|||
const DATA_DIR = process.env.DATA_DIR || './data';
|
||||
const REGISTRATIONS_FILE = path.join(DATA_DIR, 'registrations.json');
|
||||
|
||||
// Initialize Resend for emails
|
||||
const resend = process.env.RESEND_API_KEY ? new Resend(process.env.RESEND_API_KEY) : null;
|
||||
// Initialize SMTP transport (Mailcow)
|
||||
const smtp = process.env.SMTP_PASS ? nodemailer.createTransport({
|
||||
host: process.env.SMTP_HOST || 'mx.jeffemmett.com',
|
||||
port: parseInt(process.env.SMTP_PORT || '587'),
|
||||
secure: false,
|
||||
auth: {
|
||||
user: process.env.SMTP_USER || 'noreply@jeffemmett.com',
|
||||
pass: process.env.SMTP_PASS,
|
||||
},
|
||||
}) : null;
|
||||
|
||||
// Listmonk PostgreSQL configuration for newsletter management
|
||||
const LISTMONK_LIST_ID = parseInt(process.env.LISTMONK_LIST_ID) || 20; // WORLDPLAY list
|
||||
|
|
@ -109,8 +117,8 @@ async function appendToGoogleSheet(registration) {
|
|||
|
||||
// Send confirmation email
|
||||
async function sendConfirmationEmail(registration) {
|
||||
if (!resend) {
|
||||
console.log('Resend not configured, skipping email...');
|
||||
if (!smtp) {
|
||||
console.log('SMTP not configured, skipping email...');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -156,8 +164,8 @@ async function sendConfirmationEmail(registration) {
|
|||
? registration.contribute.map(c => contributeLabels[c] || c).join(', ')
|
||||
: 'Not specified';
|
||||
|
||||
await resend.emails.send({
|
||||
from: 'WORLDPLAY <hello@worldplay.art>',
|
||||
await smtp.sendMail({
|
||||
from: process.env.EMAIL_FROM || 'WORLDPLAY <noreply@jeffemmett.com>',
|
||||
to: registration.email,
|
||||
subject: '🎭 Welcome to WORLDPLAY – Registration Confirmed',
|
||||
html: `
|
||||
|
|
@ -513,7 +521,7 @@ ensureDataDir().then(() => {
|
|||
console.log(`WORLDPLAY server running on port ${PORT}`);
|
||||
console.log(`Admin token: ${process.env.ADMIN_TOKEN || 'worldplay-admin-2026'}`);
|
||||
console.log(`Google Sheets: ${sheets ? 'enabled' : 'disabled'}`);
|
||||
console.log(`Email notifications: ${resend ? 'enabled' : 'disabled'}`);
|
||||
console.log(`Email notifications: ${smtp ? 'enabled (Mailcow SMTP)' : 'disabled (no SMTP_PASS)'}`);
|
||||
console.log(`Listmonk newsletter sync: ${listmonkPool ? 'enabled' : 'disabled'} (list ID: ${LISTMONK_LIST_ID})`);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue