diff --git a/packages/@n8n/imap/src/ImapSimple.ts b/packages/@n8n/imap/src/ImapSimple.ts index eb6dc07722..dc9797507f 100644 --- a/packages/@n8n/imap/src/ImapSimple.ts +++ b/packages/@n8n/imap/src/ImapSimple.ts @@ -136,7 +136,7 @@ export class ImapSimple extends EventEmitter { const data = result.parts[0].body as string; const encoding = part.encoding.toUpperCase(); - resolve(PartData.fromData(data, encoding)); + resolve(PartData.fromData(data, encoding, part.params?.charset)); }; const fetchOnError = (error: Error) => { diff --git a/packages/@n8n/imap/src/PartData.ts b/packages/@n8n/imap/src/PartData.ts index d4ad353a97..cd69434fee 100644 --- a/packages/@n8n/imap/src/PartData.ts +++ b/packages/@n8n/imap/src/PartData.ts @@ -7,8 +7,8 @@ import * as uuencode from 'uuencode'; export abstract class PartData { constructor(readonly buffer: Buffer) {} - toString() { - return this.buffer.toString(); + toString(charset?: string) { + return iconvlite.decode(this.buffer, charset ?? 'utf-8'); } static fromData(data: string, encoding: string, charset?: string): PartData { @@ -44,10 +44,25 @@ export class Base64PartData extends PartData { } export class QuotedPrintablePartData extends PartData { + static ansiBuffer(data: string): Buffer { + const decoded = qp.decode(data); + const arr = []; + for (let index = 0; index < decoded.length; index++) { + arr.push(decoded.charCodeAt(index)); + } + return Buffer.from(arr); + } + + static utf8Buffer(data: string): Buffer { + return Buffer.from(utf8.decode(qp.decode(data))); + } + constructor(data: string, charset?: string) { const decoded = - charset?.toUpperCase() === 'UTF-8' ? utf8.decode(qp.decode(data)) : qp.decode(data); - super(Buffer.from(decoded)); + charset?.toUpperCase() === 'UTF-8' + ? QuotedPrintablePartData.utf8Buffer(data) + : QuotedPrintablePartData.ansiBuffer(data); + super(decoded); } } diff --git a/packages/@n8n/imap/test/PartData.test.ts b/packages/@n8n/imap/test/PartData.test.ts index 67d81718f3..62acc21616 100644 --- a/packages/@n8n/imap/test/PartData.test.ts +++ b/packages/@n8n/imap/test/PartData.test.ts @@ -60,6 +60,14 @@ describe('QuotedPrintablePartData', () => { }); }); +describe('QuotedPrintableGB2312PartData', () => { + it('should correctly decode quoted-printable data', () => { + const data = '=C4=E3=BA=C3=A3=AC =CA=C0=BD=E7=A3=A1'; // '你好, 世界!' in quoted-printable with gb2312 encoding + const partData = new QuotedPrintablePartData(data, 'gb2312'); + expect(partData.toString('gb2312')).toBe('你好, 世界!'); + }); +}); + describe('SevenBitPartData', () => { it('should correctly decode 7bit data', () => { const data = 'Hello, world!'; diff --git a/packages/nodes-base/nodes/EmailReadImap/v2/EmailReadImapV2.node.ts b/packages/nodes-base/nodes/EmailReadImap/v2/EmailReadImapV2.node.ts index a00d532258..d56651a731 100644 --- a/packages/nodes-base/nodes/EmailReadImap/v2/EmailReadImapV2.node.ts +++ b/packages/nodes-base/nodes/EmailReadImap/v2/EmailReadImapV2.node.ts @@ -321,7 +321,7 @@ export class EmailReadImapV2 implements INodeType { try { const partData = await connection.getPartData(message, part); - return partData.toString(); + return partData.toString(part.params?.charset); } catch { return ''; }