Skip to content

Commit 655780e

Browse files
committed
Properly insert header
1 parent 67f42b7 commit 655780e

File tree

1 file changed

+52
-5
lines changed

1 file changed

+52
-5
lines changed

lib/send-mail.ts

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,18 +186,20 @@ export async function sendMail(mail: IParsedMBox,
186186
return new Promise<string>((resolve, reject) => {
187187
const transporter = createTransport(transportOpts);
188188

189+
const rawWithHeader = addHeader(
190+
mail.raw,
191+
"X-Original-From",
192+
mail.from ?? ""
193+
);
194+
189195
// setup email data with unicode symbols
190196
const mailOptions: SendMailOptions = {
191197
envelope: {
192198
cc: mail.cc ? mail.cc.join(", ") : undefined,
193199
from: mail.from,
194200
to: mail.to,
195201
},
196-
raw: mail.raw,
197-
headers: [{
198-
key: "X-Original-From",
199-
value: mail.from ?? "",
200-
}]
202+
raw: rawWithHeader
201203
};
202204

203205
transporter.sendMail(mailOptions, (error, info: { messageId: string })
@@ -210,3 +212,48 @@ export async function sendMail(mail: IParsedMBox,
210212
});
211213
});
212214
}
215+
216+
function addHeader(raw: string, name: string, value: string): string {
217+
// Detect which newline style the source uses
218+
const CRLF = /\r\n/.test(raw) ? "\r\n" : "\n";
219+
const headerLine = `${name}: ${value}`;
220+
221+
// Split into individual lines *without* discarding line–breaks
222+
const lines = raw.split(/\r?\n/);
223+
224+
// Locate the canonical “From:” header
225+
let insertPos = -1;
226+
227+
for (let i = 0; i < lines.length; i++) {
228+
if (/^From:/i.test(lines[i])) {
229+
// Skip any folded continuation lines (start with SP / HT)
230+
insertPos = i + 1;
231+
while (insertPos < lines.length && /^[ \t]/.test(lines[insertPos])) {
232+
insertPos++;
233+
}
234+
break;
235+
}
236+
// Stop searching once we reach the blank line after headers
237+
if (lines[i] === "") break;
238+
}
239+
240+
// Determine a safe insertion point ---
241+
if (insertPos === -1) {
242+
// No From: header found – insert just before the header/body separator
243+
insertPos = lines.findIndex(l => l === "");
244+
if (insertPos === -1) {
245+
// Message is malformed (no blank line) – append one
246+
lines.push("");
247+
insertPos = lines.length - 1;
248+
}
249+
}
250+
251+
// Insert (or replace if it already exists)
252+
// Remove any existing occurrences of the header we’re about to add
253+
for (let i = lines.length - 1; i >= 0; i--) {
254+
if (new RegExp(`^${name}:`, "i").test(lines[i])) lines.splice(i, 1);
255+
}
256+
lines.splice(insertPos, 0, headerLine);
257+
258+
return lines.join(CRLF);
259+
}

0 commit comments

Comments
 (0)