fix(watcher): handle wrapped Subject lines in forwarded emails

Update the parseForwardedHeader function to correctly join wrapped Subject lines before the To: line, ensuring accurate parsing of Gmail forwarded messages. Enhance tests to validate this behavior with Tokopedia email examples.
This commit is contained in:
2026-09-14 00:04:26 +07:00
parent c446d794a8
commit 39eb1bce2f
3 changed files with 17 additions and 3 deletions
+5 -2
View File
@@ -13,6 +13,9 @@ export function extractEmail(from) {
/**
* Parse a Gmail "Forwarded message" header block from the body.
* Returns null if no forwarded header is present.
*
* Subject may wrap onto following lines without leading whitespace
* (Gmail plain-text fold), so we read until the To: line.
*/
export function parseForwardedHeader(body) {
if (!body) return null;
@@ -22,14 +25,14 @@ export function parseForwardedHeader(body) {
const after = body.slice(idx);
const headerMatch = after.match(
/From:\s*(.+)\r?\nDate:\s*(.+)\r?\nSubject:\s*(.+)\r?\nTo:\s*(.+)/i,
/From:\s*(.+)\r?\nDate:\s*(.+)\r?\nSubject:\s*([\s\S]+?)\r?\nTo:\s*(.+)/i,
);
if (!headerMatch) return null;
return {
from: headerMatch[1].trim(),
date: headerMatch[2].trim(),
subject: headerMatch[3].trim(),
subject: headerMatch[3].replace(/\s+/g, " ").trim(),
to: headerMatch[4].trim(),
};
}
+2 -1
View File
@@ -359,7 +359,8 @@ Roby
export const tokopediaMultiForwardedBody = `---------- Forwarded message ---------
From: Tokopedia <noreply@tokopedia.com>
Date: Fri, Aug 21, 2026 at 12:39 AM
Subject: Pesanan Selesai: “sandal jepit ANDA pria casual...” dan 1 Item Lainnya
Subject: Pesanan Selesai: “sandal jepit ANDA pria casual...” dan 1 Item
Lainnya
To: <nasyarobby@gmail.com>
Hai *Roby,*
+10
View File
@@ -43,6 +43,16 @@ describe("parseForwardedHeader", () => {
assert.equal(h.subject, "Pembayaran Berhasil!");
});
it("joins wrapped Subject lines before To", () => {
const h = parseForwardedHeader(tokopediaMultiForwardedBody);
assert.ok(h);
assert.match(h.from, /noreply@tokopedia\.com/);
assert.equal(
h.subject,
"Pesanan Selesai: “sandal jepit ANDA pria casual...” dan 1 Item Lainnya",
);
});
it("returns null when there is no Fwd block", () => {
assert.equal(parseForwardedHeader(livinDirectBody), null);
});