Spaces:
Sleeping
Sleeping
Codex commited on
Commit ·
10e9ccd
1
Parent(s): 6b2fff3
Add Brevo API send as primary email path with SMTP fallback
Browse files
server.js
CHANGED
|
@@ -29,6 +29,7 @@ const SMTP_HOST = process.env.SMTP_HOST || 'smtp-relay.brevo.com';
|
|
| 29 |
const SMTP_PORT = parseInt(process.env.SMTP_PORT || '587', 10);
|
| 30 |
const SMTP_SECURE = process.env.SMTP_SECURE === 'true' || SMTP_PORT === 465;
|
| 31 |
const SMTP_TIMEOUT = parseInt(process.env.SMTP_TIMEOUT_MS || '10000', 10);
|
|
|
|
| 32 |
let emailTransport = null;
|
| 33 |
let emailConfigChecked = false;
|
| 34 |
|
|
@@ -39,6 +40,46 @@ async function sendMailWithTimeout(transport, mailOptions, timeoutMs = SMTP_TIME
|
|
| 39 |
]);
|
| 40 |
}
|
| 41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
function getEmailTransport() {
|
| 43 |
if (emailTransport || emailConfigChecked) return emailTransport;
|
| 44 |
|
|
@@ -111,15 +152,43 @@ function buildAlertEmail(statusEntry) {
|
|
| 111 |
return { subject, text, html };
|
| 112 |
}
|
| 113 |
|
| 114 |
-
async function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
const transport = getEmailTransport();
|
| 116 |
-
if (!transport)
|
|
|
|
|
|
|
| 117 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
const { subject, text, html } = buildAlertEmail(statusEntry);
|
| 119 |
const emailFrom = process.env.EMAIL_FROM;
|
| 120 |
const emailTo = process.env.EMAIL_TO;
|
| 121 |
|
| 122 |
-
await
|
| 123 |
from: emailFrom,
|
| 124 |
to: emailTo,
|
| 125 |
subject,
|
|
@@ -226,22 +295,14 @@ function buildStatusReportEmail() {
|
|
| 226 |
async function sendStatusReportEmail() {
|
| 227 |
const emailFrom = process.env.EMAIL_FROM;
|
| 228 |
const emailTo = process.env.EMAIL_TO;
|
| 229 |
-
const smtpUser = process.env.SMTP_USER || emailFrom;
|
| 230 |
-
const smtpPass = process.env.SMTP_PASS || process.env.BREVO_SMTP_PASS || process.env.BREVO_API_KEY;
|
| 231 |
|
| 232 |
-
if (!emailFrom || !emailTo
|
| 233 |
-
throw new Error('Brak konfiguracji e-mail: ustaw EMAIL_FROM
|
| 234 |
-
}
|
| 235 |
-
|
| 236 |
-
const transport = getEmailTransport();
|
| 237 |
-
if (!transport) {
|
| 238 |
-
throw new Error('Transport e-mail nie jest dostępny.');
|
| 239 |
}
|
| 240 |
|
| 241 |
const { subject, text, html } = buildStatusReportEmail();
|
| 242 |
-
console.log(`Sending status report email via ${SMTP_HOST}:${SMTP_PORT} secure=${SMTP_SECURE} as ${smtpUser} to ${emailTo}, timeout ${SMTP_TIMEOUT}ms`);
|
| 243 |
|
| 244 |
-
await
|
| 245 |
from: emailFrom,
|
| 246 |
to: emailTo,
|
| 247 |
subject,
|
|
|
|
| 29 |
const SMTP_PORT = parseInt(process.env.SMTP_PORT || '587', 10);
|
| 30 |
const SMTP_SECURE = process.env.SMTP_SECURE === 'true' || SMTP_PORT === 465;
|
| 31 |
const SMTP_TIMEOUT = parseInt(process.env.SMTP_TIMEOUT_MS || '10000', 10);
|
| 32 |
+
const BREVO_API_TIMEOUT = parseInt(process.env.BREVO_API_TIMEOUT_MS || '10000', 10);
|
| 33 |
let emailTransport = null;
|
| 34 |
let emailConfigChecked = false;
|
| 35 |
|
|
|
|
| 40 |
]);
|
| 41 |
}
|
| 42 |
|
| 43 |
+
async function sendViaBrevoApi(message) {
|
| 44 |
+
const apiKey = process.env.BREVO_API_KEY;
|
| 45 |
+
if (!apiKey) {
|
| 46 |
+
throw new Error('Brak BREVO_API_KEY do wysyłki przez API.');
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
const recipients = (message.to || '')
|
| 50 |
+
.split(',')
|
| 51 |
+
.map(s => s.trim())
|
| 52 |
+
.filter(Boolean)
|
| 53 |
+
.map(email => ({ email }));
|
| 54 |
+
|
| 55 |
+
if (recipients.length === 0) {
|
| 56 |
+
throw new Error('Brak odbiorców e-mail (EMAIL_TO).');
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
const payload = {
|
| 60 |
+
sender: { email: message.from },
|
| 61 |
+
to: recipients,
|
| 62 |
+
subject: message.subject,
|
| 63 |
+
textContent: message.text,
|
| 64 |
+
htmlContent: message.html
|
| 65 |
+
};
|
| 66 |
+
|
| 67 |
+
await axios.post(
|
| 68 |
+
'https://api.brevo.com/v3/smtp/email',
|
| 69 |
+
payload,
|
| 70 |
+
{
|
| 71 |
+
headers: {
|
| 72 |
+
'api-key': apiKey,
|
| 73 |
+
accept: 'application/json',
|
| 74 |
+
'content-type': 'application/json'
|
| 75 |
+
},
|
| 76 |
+
timeout: BREVO_API_TIMEOUT
|
| 77 |
+
}
|
| 78 |
+
);
|
| 79 |
+
|
| 80 |
+
console.log('Email sent via Brevo API');
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
function getEmailTransport() {
|
| 84 |
if (emailTransport || emailConfigChecked) return emailTransport;
|
| 85 |
|
|
|
|
| 152 |
return { subject, text, html };
|
| 153 |
}
|
| 154 |
|
| 155 |
+
async function sendEmail(message) {
|
| 156 |
+
const emailFrom = process.env.EMAIL_FROM;
|
| 157 |
+
const emailTo = process.env.EMAIL_TO;
|
| 158 |
+
if (!emailFrom || !emailTo) {
|
| 159 |
+
throw new Error('Brak EMAIL_FROM/EMAIL_TO do wysyłki e-mail.');
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
// Prefer Brevo API if key is available
|
| 163 |
+
if (process.env.BREVO_API_KEY) {
|
| 164 |
+
try {
|
| 165 |
+
await sendViaBrevoApi(message);
|
| 166 |
+
return;
|
| 167 |
+
} catch (err) {
|
| 168 |
+
console.error('Brevo API send failed, falling back to SMTP if available:', err && err.message ? err.message : err);
|
| 169 |
+
}
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
const transport = getEmailTransport();
|
| 173 |
+
if (!transport) {
|
| 174 |
+
throw new Error('Brak transportu e-mail (SMTP/API).');
|
| 175 |
+
}
|
| 176 |
|
| 177 |
+
await sendMailWithTimeout(transport, {
|
| 178 |
+
from: message.from,
|
| 179 |
+
to: message.to,
|
| 180 |
+
subject: message.subject,
|
| 181 |
+
text: message.text,
|
| 182 |
+
html: message.html
|
| 183 |
+
});
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
async function sendAlertEmail(statusEntry) {
|
| 187 |
const { subject, text, html } = buildAlertEmail(statusEntry);
|
| 188 |
const emailFrom = process.env.EMAIL_FROM;
|
| 189 |
const emailTo = process.env.EMAIL_TO;
|
| 190 |
|
| 191 |
+
await sendEmail({
|
| 192 |
from: emailFrom,
|
| 193 |
to: emailTo,
|
| 194 |
subject,
|
|
|
|
| 295 |
async function sendStatusReportEmail() {
|
| 296 |
const emailFrom = process.env.EMAIL_FROM;
|
| 297 |
const emailTo = process.env.EMAIL_TO;
|
|
|
|
|
|
|
| 298 |
|
| 299 |
+
if (!emailFrom || !emailTo) {
|
| 300 |
+
throw new Error('Brak konfiguracji e-mail: ustaw EMAIL_FROM i EMAIL_TO.');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 301 |
}
|
| 302 |
|
| 303 |
const { subject, text, html } = buildStatusReportEmail();
|
|
|
|
| 304 |
|
| 305 |
+
await sendEmail({
|
| 306 |
from: emailFrom,
|
| 307 |
to: emailTo,
|
| 308 |
subject,
|