I’ve built a Gmail workflow in n8n that automatically forwards incoming emails. It’s mostly working — I receive the forwarded messages, but:
The forwarded emails always say:
Subject: Forward: No Subject
Body: No email body found.
Even though the original emails have a subject and a full HTML body.
What I’ve Tried
Trigger: Gmail Trigger set to poll daily via messageReceived
Extractor: Gmail Get Message node with attachments disabled
Decoder: Code node that looks for payload.parts or payload.body.data, and decodes base64
Subject: Pulled from payload.headers.find(h => h.name === ‘Subject’)?.value
Sender: Send Message node using {{ $json.subject }} and {{ $json.decodedBody }}
function findBody(part) {
if (!part) return null;
if (part.mimeType === 'text/html' || part.mimeType === 'text/plain') {
return part.body?.data || null;
}
if (Array.isArray(part.parts)) {
for (const sub of part.parts) {
const found = findBody(sub);
if (found) return found;
}
}
return null;
}
const payload = $json.payload || {};
let rawContent = findBody(payload);
if (!rawContent && payload.body?.data) {
rawContent = payload.body.data;
}
const decoded = rawContent
? Buffer.from(rawContent, 'base64').toString('utf-8')
: '<p>No email body found.</p>';
const headers = payload.headers || [];
const subject = headers.find(h => h.name === 'Subject')?.value || 'No Subject';
return {
json: {
subject,
decodedBody: decoded
}
};
The raw email from the Get Message node does include subject, text, and html fields, but the forwarded email still defaults to “No Subject” and “No email body found.”
Another Issue: Getting Duplicate Emails
When the workflow runs live on a poll schedule, I sometimes get multiple emails forwarded from the same message, even though they’re marked as read.
Any tips on how to ensure each message is processed just once? Is there something I should be setting with label filters, deduplication, or memory?
I’m only trying to forward specific emails (like invoices), which are labeled in Gmail. But because Gmail formats vary, especially for forwarded or multi-part messages. I added a Code node to make sure I can consistently extract:
the real subject (from headers), and
the actual message body (even if it’s buried in nested parts or encoded)
Without it, the “Send Email” step was showing No Subject and No email body found, even though the email clearly had content.
Hope that gives some context! Here’s the code’s js:
function findBody(part) {
if (!part) return null;
if (part.mimeType === 'text/html' || part.mimeType === 'text/plain') {
return part.body?.data || null;
}
if (Array.isArray(part.parts)) {
for (const sub of part.parts) {
const found = findBody(sub);
if (found) return found;
}
}
return null;
}
const payload = $json.payload || {};
let rawContent = findBody(payload);
// fallback if no parts found
if (!rawContent && payload.body?.data) {
rawContent = payload.body.data;
}
const decoded = rawContent
? Buffer.from(rawContent, 'base64').toString('utf-8')
: '<p>No email body found.</p>';
// grab subject from header array
const headers = payload.headers || [];
const subjectHeader = headers.find(h => h.name?.toLowerCase() === 'subject');
const subject = subjectHeader?.value?.trim() || 'No Subject';
return {
json: {
subject,
decodedBody: decoded
}
};
hi @DRGN79 , okay thank you for the explanation, now i understand, can you maybe give me the example email so i can test this code as well, there might be something wrong in the code, that it’s not fetching the right part and resulted in no header and no body
Here’s an example invoice email I receive — I’ve redacted identifying info and attached just the PDF. These types of emails almost always contain a PDF invoice, and are labeled in Gmail as Invoices so my workflow knows to process them.
The goal of the automation is to extract the subject, body, and attachments, and forward these to an assistant’s inbox for tracking.
Right now the workflow is working technically, but many of the emails still get forwarded as:
Subject: Forward: No Subject
Body: No email body found.
Let me know if anything jumps out with the structure or MIME format of this sample. I’d love to know if there’s a better way to decode these, especially the subject and body — to avoid missing info like this.