Skip to content

Commit fe27f7f

Browse files
committed
fix: merge fragmented display names with unquoted commas in addressparser
1 parent 1dd8eeb commit fe27f7f

2 files changed

Lines changed: 74 additions & 0 deletions

File tree

lib/addressparser/index.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,20 @@ function addressparser(str, options) {
361361
}
362362
});
363363

364+
// Merge fragments from unquoted display names containing commas/semicolons.
365+
// When "Joe Foo, PhD <joe@example.com>" is split on the comma, it produces
366+
// [{name:"Joe Foo", address:""}, {name:"PhD", address:"joe@example.com"}].
367+
// Detect this pattern and recombine: a name-only entry followed by an entry
368+
// that has both a name and an address (from angle-bracket notation).
369+
for (let i = parsedAddresses.length - 2; i >= 0; i--) {
370+
let current = parsedAddresses[i];
371+
let next = parsedAddresses[i + 1];
372+
if (current.address === '' && current.name && !current.group && next.address && next.name && !next.group) {
373+
next.name = current.name + ', ' + next.name;
374+
parsedAddresses.splice(i, 1);
375+
}
376+
}
377+
364378
if (options.flatten) {
365379
let addresses = [];
366380
let walkAddressList = list => {

test/addressparser/addressparser-test.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,66 @@ describe('#addressparser', () => {
775775
});
776776
});
777777

778+
// Unquoted display names with commas (GitHub issue nodemailer/mailparser#375)
779+
describe('Unquoted display names with commas', () => {
780+
it('should merge comma-separated name parts with angle-bracket address', () => {
781+
let input = 'Joe Foo, PhD <joe@example.com>';
782+
let expected = [{ name: 'Joe Foo, PhD', address: 'joe@example.com' }];
783+
assert.deepStrictEqual(addressparser(input), expected);
784+
});
785+
786+
it('should merge multiple comma-separated name parts', () => {
787+
let input = 'A, B, C <d@e.com>';
788+
let expected = [{ name: 'A, B, C', address: 'd@e.com' }];
789+
assert.deepStrictEqual(addressparser(input), expected);
790+
});
791+
792+
it('should merge multiple recipients with commas in names', () => {
793+
let input = 'Joe, PhD <j@e.com>, Jane, MD <jane@e.com>';
794+
let expected = [
795+
{ name: 'Joe, PhD', address: 'j@e.com' },
796+
{ name: 'Jane, MD', address: 'jane@e.com' }
797+
];
798+
assert.deepStrictEqual(addressparser(input), expected);
799+
});
800+
801+
it('should handle bare emails mixed with comma-in-name addresses', () => {
802+
let input = 'a@b.com, Foo, Bar <c@d.com>, e@f.com';
803+
let expected = [
804+
{ name: '', address: 'a@b.com' },
805+
{ name: 'Foo, Bar', address: 'c@d.com' },
806+
{ name: '', address: 'e@f.com' }
807+
];
808+
assert.deepStrictEqual(addressparser(input), expected);
809+
});
810+
811+
it('should not merge when bare email follows a name (no angle brackets)', () => {
812+
let input = 'SomeName, joe@example.com';
813+
let result = addressparser(input);
814+
// Bare email produces empty name, so no merge should happen
815+
assert.strictEqual(result.length, 2);
816+
assert.strictEqual(result[0].name, 'SomeName');
817+
assert.strictEqual(result[0].address, '');
818+
assert.strictEqual(result[1].address, 'joe@example.com');
819+
assert.strictEqual(result[1].name, '');
820+
});
821+
822+
it('should not merge when group is involved', () => {
823+
let input = 'Title, Group: a@b.com;';
824+
let result = addressparser(input);
825+
assert.strictEqual(result.length, 2);
826+
assert.strictEqual(result[0].name, 'Title');
827+
assert.strictEqual(result[1].name, 'Group');
828+
assert.ok(result[1].group);
829+
});
830+
831+
it('should not regress quoted names with commas', () => {
832+
let input = '"Joe, PhD" <joe@example.com>';
833+
let expected = [{ name: 'Joe, PhD', address: 'joe@example.com' }];
834+
assert.deepStrictEqual(addressparser(input), expected);
835+
});
836+
});
837+
778838
// DoS protection tests for deeply nested groups (CVE-like vulnerability fix)
779839
describe('Nested group DoS protection', () => {
780840
/**

0 commit comments

Comments
 (0)