diff --git a/Captura de tela 2025-10-07 150744.png b/Captura de tela 2025-10-07 150744.png deleted file mode 100644 index 2828187..0000000 Binary files a/Captura de tela 2025-10-07 150744.png and /dev/null differ diff --git a/Inter,Manrope.zip b/Inter,Manrope.zip deleted file mode 100644 index 813604f..0000000 Binary files a/Inter,Manrope.zip and /dev/null differ diff --git a/src/server/email-smtp.ts b/src/server/email-smtp.ts index 85f15be..42c87af 100644 --- a/src/server/email-smtp.ts +++ b/src/server/email-smtp.ts @@ -13,6 +13,20 @@ function b64(input: string) { return Buffer.from(input, "utf8").toString("base64") } +function extractEnvelopeAddress(from: string): string { + // Prefer address inside angle brackets + const angle = from.match(/<\s*([^>\s]+)\s*>/) + if (angle?.[1]) return angle[1] + // Fallback: address inside parentheses + const paren = from.match(/\(([^)\s]+@[^)\s]+)\)/) + if (paren?.[1]) return paren[1] + // Fallback: first email-like substring + const email = from.match(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/) + if (email?.[0]) return email[0] + // Last resort: use whole string + return from +} + export async function sendSmtpMail(cfg: SmtpConfig, to: string, subject: string, html: string) { return new Promise((resolve, reject) => { const socket = tls.connect(cfg.port, cfg.host, { rejectUnauthorized: false }, () => { @@ -44,7 +58,8 @@ export async function sendSmtpMail(cfg: SmtpConfig, to: string, subject: string, await wait(/^334 /) send(b64(cfg.password)) await wait(/^235 /) - send(`MAIL FROM:<${cfg.from.match(/<(.+)>/)?.[1] ?? cfg.from}>`) + const envelopeFrom = extractEnvelopeAddress(cfg.from) + send(`MAIL FROM:<${envelopeFrom}>`) await wait(/^250 /) send(`RCPT TO:<${to}>`) await wait(/^250 /) diff --git a/tests/email-smtp.test.ts b/tests/email-smtp.test.ts index f9bc261..93a491c 100644 --- a/tests/email-smtp.test.ts +++ b/tests/email-smtp.test.ts @@ -1,6 +1,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest" // Mock tls to simulate an SMTP server over implicit TLS +let lastWrites: string[] = [] vi.mock("tls", () => { class MockSocket { listeners: Record = {} @@ -58,6 +59,7 @@ vi.mock("tls", () => { function connect(_port: number, _host: string, _opts: unknown, cb?: Function) { const socket = new MockSocket() + lastWrites = socket.writes // initial server greeting setTimeout(() => { cb?.() @@ -66,7 +68,7 @@ vi.mock("tls", () => { return socket as unknown as NodeJS.WritableStream & { on: MockSocket["on"] } } - return { default: { connect }, connect } + return { default: { connect }, connect, __getLastWrites: () => lastWrites } }) describe("sendSmtpMail", () => { @@ -87,5 +89,23 @@ describe("sendSmtpMail", () => { ) ).resolves.toBeUndefined() }) -}) + it("extracts envelope address from parentheses or raw email", async () => { + const { sendSmtpMail } = await import("@/server/email-smtp") + const tlsMock = await import("tls" as any) + await sendSmtpMail( + { + host: "smtp.mock", + port: 465, + username: "user@example.com", + password: "secret", + from: "Chatwoot chat@esdrasrenan.com.br (chat@esdrasrenan.com.br)", + }, + "rcpt@example.com", + "Subject", + "

Hi

" + ) + const writes = (tlsMock as any).__getLastWrites() as string[] + expect(writes.some((w) => /MAIL FROM:\r\n/.test(w))).toBe(true) + }) +})