Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for commas and semicolons in email name and add test #511

Merged
merged 1 commit into from
Mar 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 62 additions & 6 deletions lib/helpers/mail/Mail.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ class ReplyTo implements \JsonSerializable

public function __construct($email, $name = null)
{
$this->email = $email;
$this->setEmail($email);

if (!is_null($name)) {
$this->name = $name;
$this->setName($name);
}
}

Expand All @@ -38,7 +38,35 @@ public function getEmail()

public function setName($name)
{
$this->name = $name;
/*
Issue #368
==========

If the name is not wrapped in double quotes and contains a comma or
semicolon, the API fails to parse it correctly.

When wrapped in double quotes, commas, semicolons and unescaped single
quotes are supported.
Escaped double quotes are supported as well but will appear unescaped in
the mail (e.g. "O\'Keefe").

Double quotes will be shown in some email clients, so the name should
only be wrapped when necessary.
*/

// Only wrapp in double quote if comma or semicolon are found
if (false !== strpos($name, ',') || false !== strpos($name, ';')) {
// Unescape quotes
$name = stripslashes(html_entity_decode($name, ENT_QUOTES));

// Escape only double quotes
$name = str_replace('"', '\\"', $name);

// Wrapp in double quotes
$name = '"' . $name . '"';
}

$this->name = (!empty($name)) ? $name : null;
}

public function getName()
Expand Down Expand Up @@ -897,13 +925,41 @@ class Email implements \JsonSerializable

public function __construct($name, $email)
{
$this->name = $name;
$this->email = $email;
$this->setName($name);
$this->setEmail($email);
}

public function setName($name)
{
$this->name = $name;
/*
Issue #368
==========

If the name is not wrapped in double quotes and contains a comma or
semicolon, the API fails to parse it correctly.

When wrapped in double quotes, commas, semicolons and unescaped single
quotes are supported.
Escaped double quotes are supported as well but will appear unescaped in
the mail (e.g. "O\'Keefe").

Double quotes will be shown in some email clients, so the name should
only be wrapped when necessary.
*/

// Only wrapp in double quote if comma or semicolon are found
if (false !== strpos($name, ',') || false !== strpos($name, ';')) {
// Unescape quotes
$name = stripslashes(html_entity_decode($name, ENT_QUOTES));

// Escape only double quotes
$name = str_replace('"', '\\"', $name);

// Wrapp in double quotes
$name = '"' . $name . '"';
}

$this->name = (!empty($name)) ? $name : null;
}

public function getName()
Expand Down
31 changes: 31 additions & 0 deletions test/unit/Mail/MailHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,35 @@ public function testKitchenSinkExample()

$this->assertEquals($json, '{"from":{"name":"DX","email":"test@example.com"},"personalizations":[{"to":[{"name":"Example User","email":"test@example.com"},{"name":"Example User","email":"test@example.com"}],"cc":[{"name":"Example User","email":"test@example.com"},{"name":"Example User","email":"test@example.com"}],"bcc":[{"name":"Example User","email":"test@example.com"},{"name":"Example User","email":"test@example.com"}],"subject":"Hello World from the SendGrid PHP Library","headers":{"X-Test":"test","X-Mock":"true"},"substitutions":{"%name%":"Example User","%city%":"Denver"},"custom_args":{"user_id":"343","type":"marketing"},"send_at":1443636843},{"to":[{"name":"Example User","email":"test@example.com"},{"name":"Example User","email":"test@example.com"}],"cc":[{"name":"Example User","email":"test@example.com"},{"name":"Example User","email":"test@example.com"}],"bcc":[{"name":"Example User","email":"test@example.com"},{"name":"Example User","email":"test@example.com"}],"subject":"Hello World from the SendGrid PHP Library","headers":{"X-Test":"test","X-Mock":"true"},"substitutions":{"%name%":"Example User","%city%":"Denver"},"custom_args":{"user_id":"343","type":"marketing"},"send_at":1443636843}],"subject":"Hello World from the SendGrid PHP Library","content":[{"type":"text\/plain","value":"some text here"},{"type":"text\/html","value":"<html><body>some text here<\/body><\/html>"}],"attachments":[{"content":"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4gQ3JhcyBwdW12","type":"application\/pdf","filename":"balance_001.pdf","disposition":"attachment","content_id":"Balance Sheet"},{"content":"BwdW","type":"image\/png","filename":"banner.png","disposition":"inline","content_id":"Banner"}],"template_id":"439b6d66-4408-4ead-83de-5c83c2ee313a","sections":{"%section1%":"Substitution Text for Section 1","%section2%":"Substitution Text for Section 2"},"headers":{"X-Test1":"1","X-Test2":"2"},"categories":["May","2016"],"custom_args":{"campaign":"welcome","weekday":"morning"},"send_at":1443636842,"asm":{"group_id":99,"groups_to_display":[4,5,6,7,8]},"ip_pool_name":"23","mail_settings":{"bcc":{"enable":true,"email":"test@example.com"},"bypass_list_management":{"enable":true},"footer":{"enable":true,"text":"Footer Text","html":"<html><body>Footer Text<\/body><\/html>"},"sandbox_mode":{"enable":true},"spam_check":{"enable":true,"threshold":1,"post_to_url":"https:\/\/spamcatcher.sendgrid.com"}},"tracking_settings":{"click_tracking":{"enable":true,"enable_text":true},"open_tracking":{"enable":true,"substitution_tag":"Optional tag to replace with the open image in the body of the message"},"subscription_tracking":{"enable":true,"text":"text to insert into the text\/plain portion of the message","html":"<html><body>html to insert into the text\/html portion of the message<\/body><\/html>","substitution_tag":"Optional tag to replace with the open image in the body of the message"},"ganalytics":{"enable":true,"utm_source":"some source","utm_medium":"some medium","utm_term":"some term","utm_content":"some content","utm_campaign":"some name"}},"reply_to":{"email":"test@example.com"}}');
}

public function testEmailName()
{
$email = new Email('John Doe', 'test@example.com');
$json = json_encode($email->jsonSerialize());
$this->assertEquals($json, '{"name":"John Doe","email":"test@example.com"}');

$email->setName('');
$json = json_encode($email->jsonSerialize());
$this->assertEquals($json, '{"email":"test@example.com"}');

$email->setName(null);
$json = json_encode($email->jsonSerialize());
$this->assertEquals($json, '{"email":"test@example.com"}');

$email->setName('Doe, John');
$json = json_encode($email->jsonSerialize());
$this->assertEquals($json, '{"name":"\\"Doe, John\\"","email":"test@example.com"}');

$email->setName('Doe; John');
$json = json_encode($email->jsonSerialize());
$this->assertEquals($json, '{"name":"\\"Doe; John\\"","email":"test@example.com"}');

$email->setName('John "Billy" O\'Keeffe');
$json = json_encode($email->jsonSerialize());
$this->assertEquals($json, '{"name":"John \\"Billy\\" O\'Keeffe","email":"test@example.com"}');

$email->setName('O\'Keeffe, John "Billy"');
$json = json_encode($email->jsonSerialize());
$this->assertEquals($json, '{"name":"\\"O\'Keeffe, John \\\\\\"Billy\\\\\\"\\"","email":"test@example.com"}');
}
}