diff --git a/app/bundles/EmailBundle/Helper/MailHelper.php b/app/bundles/EmailBundle/Helper/MailHelper.php index 9a33842f58b..cb22ebe1d4c 100644 --- a/app/bundles/EmailBundle/Helper/MailHelper.php +++ b/app/bundles/EmailBundle/Helper/MailHelper.php @@ -1252,17 +1252,18 @@ public function setFrom($address, $name = null) */ public static function validateEmail($address) { - static $grammer; + $invalidChar = strpbrk($address, '\'^&*%'); - if ($grammer === null) { - $grammer = new \Swift_Mime_Grammar(); + if ($invalidChar !== false) { + throw new \Swift_RfcComplianceException( + 'Email address ['.$address. + '] contains this invalid character: '.substr($invalidChar, 0, 1) + ); } - if (!preg_match('/^'.$grammer->getDefinition('addr-spec').'$/D', - $address)) { + if (!filter_var($address, FILTER_VALIDATE_EMAIL)) { throw new \Swift_RfcComplianceException( - 'Address in mailbox given ['.$address. - '] does not comply with RFC 2822, 3.6.2.' + 'Email address ['.$address.'] is invalid' ); } } diff --git a/app/bundles/EmailBundle/Tests/Helper/MailHelperTest.php b/app/bundles/EmailBundle/Tests/Helper/MailHelperTest.php index e941ca738aa..2ff24b4de3f 100644 --- a/app/bundles/EmailBundle/Tests/Helper/MailHelperTest.php +++ b/app/bundles/EmailBundle/Tests/Helper/MailHelperTest.php @@ -13,6 +13,7 @@ use Mautic\CoreBundle\Factory\MauticFactory; use Mautic\EmailBundle\Entity\Email; +use Mautic\EmailBundle\Helper\MailHelper; use Mautic\EmailBundle\MonitoredEmail\Mailbox; use Mautic\EmailBundle\Swiftmailer\Exception\BatchQueueMaxException; use Mautic\EmailBundle\Tests\Helper\Transport\BatchTransport; @@ -79,7 +80,7 @@ public function testQueueModeThrowsExceptionWhenBatchLimitHit() $swiftMailer = new \Swift_Mailer(new BatchTransport()); - $mailer = new \Mautic\EmailBundle\Helper\MailHelper($mockFactory, $swiftMailer, ['nobody@nowhere.com' => 'No Body']); + $mailer = new MailHelper($mockFactory, $swiftMailer, ['nobody@nowhere.com' => 'No Body']); // Enable queue mode $mailer->enableQueue(); @@ -107,7 +108,7 @@ public function testQueueModeDisabledDoesNotThrowsExceptionWhenBatchLimitHit() $swiftMailer = new \Swift_Mailer(new BatchTransport()); - $mailer = new \Mautic\EmailBundle\Helper\MailHelper($mockFactory, $swiftMailer, ['nobody@nowhere.com' => 'No Body']); + $mailer = new MailHelper($mockFactory, $swiftMailer, ['nobody@nowhere.com' => 'No Body']); // Enable queue mode try { @@ -128,7 +129,7 @@ public function testQueuedEmailFromOverride() $transport = new BatchTransport(); $swiftMailer = new \Swift_Mailer($transport); - $mailer = new \Mautic\EmailBundle\Helper\MailHelper($mockFactory, $swiftMailer, ['nobody@nowhere.com' => 'No Body']); + $mailer = new MailHelper($mockFactory, $swiftMailer, ['nobody@nowhere.com' => 'No Body']); $mailer->enableQueue(); $email = new Email(); @@ -169,7 +170,7 @@ public function testBatchMode() $transport = new BatchTransport(true); $swiftMailer = new \Swift_Mailer($transport); - $mailer = new \Mautic\EmailBundle\Helper\MailHelper($mockFactory, $swiftMailer, ['nobody@nowhere.com' => 'No Body']); + $mailer = new MailHelper($mockFactory, $swiftMailer, ['nobody@nowhere.com' => 'No Body']); $mailer->enableQueue(); $email = new Email(); @@ -200,7 +201,7 @@ public function testQueuedOwnerAsMailer() $transport = new BatchTransport(); $swiftMailer = new \Swift_Mailer($transport); - $mailer = new \Mautic\EmailBundle\Helper\MailHelper($mockFactory, $swiftMailer, ['nobody@nowhere.com' => 'No Body']); + $mailer = new MailHelper($mockFactory, $swiftMailer, ['nobody@nowhere.com' => 'No Body']); $mailer->enableQueue(); $mailer->setSubject('Hello'); @@ -255,7 +256,7 @@ public function testStandardOwnerAsMailer() $transport = new SmtpTransport(); $swiftMailer = new \Swift_Mailer($transport); - $mailer = new \Mautic\EmailBundle\Helper\MailHelper($mockFactory, $swiftMailer, ['nobody@nowhere.com' => 'No Body']); + $mailer = new MailHelper($mockFactory, $swiftMailer, ['nobody@nowhere.com' => 'No Body']); $mailer->setBody('{signature}'); foreach ($this->contacts as $key => $contact) { @@ -276,6 +277,88 @@ public function testStandardOwnerAsMailer() } } + public function testValidateValidEmails() + { + $helper = $this->mockEmptyMailHelper(); + $addresses = [ + 'john@doe.com', + 'john@doe.email', + 'john.doe@email.com', + 'john+doe@email.com', + 'john@doe.whatevertldtheycomewithinthefuture', + ]; + + foreach ($addresses as $address) { + // will throw Swift_RfcComplianceException if it will find the address invalid + $helper::validateEmail($address); + } + } + + public function testValidateEmailWithoutTld() + { + $heper = $this->mockEmptyMailHelper(); + $this->setExpectedException(\Swift_RfcComplianceException::class); + $heper::validateEmail('john@doe'); + } + + public function testValidateEmailWithSpaceInIt() + { + $heper = $this->mockEmptyMailHelper(); + $this->setExpectedException(\Swift_RfcComplianceException::class); + $heper::validateEmail('jo hn@doe.email'); + } + + public function testValidateEmailWithCaretInIt() + { + $heper = $this->mockEmptyMailHelper(); + $this->setExpectedException(\Swift_RfcComplianceException::class); + $heper::validateEmail('jo^hn@doe.email'); + } + + public function testValidateEmailWithApostropheInIt() + { + $heper = $this->mockEmptyMailHelper(); + $this->setExpectedException(\Swift_RfcComplianceException::class); + $heper::validateEmail('jo\'hn@doe.email'); + } + + public function testValidateEmailWithSemicolonInIt() + { + $heper = $this->mockEmptyMailHelper(); + $this->setExpectedException(\Swift_RfcComplianceException::class); + $heper::validateEmail('jo;hn@doe.email'); + } + + public function testValidateEmailWithAmpersandInIt() + { + $heper = $this->mockEmptyMailHelper(); + $this->setExpectedException(\Swift_RfcComplianceException::class); + $heper::validateEmail('jo&hn@doe.email'); + } + + public function testValidateEmailWithStarInIt() + { + $heper = $this->mockEmptyMailHelper(); + $this->setExpectedException(\Swift_RfcComplianceException::class); + $heper::validateEmail('jo*hn@doe.email'); + } + + public function testValidateEmailWithPercentInIt() + { + $heper = $this->mockEmptyMailHelper(); + $this->setExpectedException(\Swift_RfcComplianceException::class); + $heper::validateEmail('jo%hn@doe.email'); + } + + protected function mockEmptyMailHelper() + { + $mockFactory = $this->getMockFactory(); + $transport = new SmtpTransport(); + $swiftMailer = new \Swift_Mailer($transport); + + return new MailHelper($mockFactory, $swiftMailer); + } + protected function getMockFactory($mailIsOwner = true) { $mockLeadRepository = $this->getMockBuilder(LeadRepository::class)