MailTest.php 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Mail
  17. * @subpackage UnitTests
  18. * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id $
  21. */
  22. /**
  23. * Test helper
  24. */
  25. require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'TestHelper.php';
  26. /**
  27. * Zend_Mail
  28. */
  29. require_once 'Zend/Mail.php';
  30. /**
  31. * Zend_Mail_Transport_Abstract
  32. */
  33. require_once 'Zend/Mail/Transport/Abstract.php';
  34. /**
  35. * Zend_Mail_Transport_Sendmail
  36. */
  37. require_once 'Zend/Mail/Transport/Sendmail.php';
  38. /**
  39. * Zend_Mail_Transport_Smtp
  40. */
  41. require_once 'Zend/Mail/Transport/Smtp.php';
  42. /**
  43. * Zend_Date
  44. */
  45. require_once 'Zend/Date.php';
  46. /**
  47. * Mock mail transport class for testing purposes
  48. *
  49. * @category Zend
  50. * @package Zend_Mail
  51. * @subpackage UnitTests
  52. * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  53. * @license http://framework.zend.com/license/new-bsd New BSD License
  54. */
  55. class Zend_Mail_Transport_Mock extends Zend_Mail_Transport_Abstract
  56. {
  57. /**
  58. * @var Zend_Mail
  59. */
  60. public $mail = null;
  61. public $returnPath = null;
  62. public $subject = null;
  63. public $from = null;
  64. public $headers = null;
  65. public $called = false;
  66. public function _sendMail()
  67. {
  68. $this->mail = $this->_mail;
  69. $this->subject = $this->_mail->getSubject();
  70. $this->from = $this->_mail->getFrom();
  71. $this->returnPath = $this->_mail->getReturnPath();
  72. $this->headers = $this->_headers;
  73. $this->called = true;
  74. }
  75. }
  76. /**
  77. * Mock mail transport class for testing Sendmail transport
  78. *
  79. * @category Zend
  80. * @package Zend_Mail
  81. * @subpackage UnitTests
  82. * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  83. * @license http://framework.zend.com/license/new-bsd New BSD License
  84. */
  85. class Zend_Mail_Transport_Sendmail_Mock extends Zend_Mail_Transport_Sendmail
  86. {
  87. /**
  88. * @var Zend_Mail
  89. */
  90. public $mail = null;
  91. public $from = null;
  92. public $subject = null;
  93. public $called = false;
  94. public function _sendMail()
  95. {
  96. $this->mail = $this->_mail;
  97. $this->from = $this->_mail->getFrom();
  98. $this->subject = $this->_mail->getSubject();
  99. $this->called = true;
  100. }
  101. }
  102. /**
  103. * @category Zend
  104. * @package Zend_Mail
  105. * @subpackage UnitTests
  106. * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  107. * @license http://framework.zend.com/license/new-bsd New BSD License
  108. * @group Zend_Mail
  109. */
  110. class Zend_Mail_MailTest extends PHPUnit_Framework_TestCase
  111. {
  112. /**
  113. * Test case for a simple email text message with
  114. * multiple recipients.
  115. *
  116. */
  117. public function testOnlyText()
  118. {
  119. $mail = new Zend_Mail();
  120. $res = $mail->setBodyText('This is a test.');
  121. $mail->setFrom('testmail@example.com', 'test Mail User');
  122. $mail->setSubject('My Subject');
  123. $mail->addTo('recipient1@example.com');
  124. $mail->addTo('recipient2@example.com');
  125. $mail->addBcc('recipient1_bcc@example.com');
  126. $mail->addBcc('recipient2_bcc@example.com');
  127. $mail->addCc('recipient1_cc@example.com', 'Example no. 1 for cc');
  128. $mail->addCc('recipient2_cc@example.com', 'Example no. 2 for cc');
  129. $mock = new Zend_Mail_Transport_Mock();
  130. $mail->send($mock);
  131. $this->assertTrue($mock->called);
  132. $this->assertEquals('My Subject', $mock->subject);
  133. $this->assertEquals('testmail@example.com', $mock->from);
  134. $this->assertContains('recipient1@example.com', $mock->recipients);
  135. $this->assertContains('recipient2@example.com', $mock->recipients);
  136. $this->assertContains('recipient1_bcc@example.com', $mock->recipients);
  137. $this->assertContains('recipient2_bcc@example.com', $mock->recipients);
  138. $this->assertContains('recipient1_cc@example.com', $mock->recipients);
  139. $this->assertContains('recipient2_cc@example.com', $mock->recipients);
  140. $this->assertContains('This is a test.', $mock->body);
  141. $this->assertContains('Content-Transfer-Encoding: quoted-printable', $mock->header);
  142. $this->assertContains('Content-Type: text/plain', $mock->header);
  143. $this->assertContains('From: test Mail User <testmail@example.com>', $mock->header);
  144. $this->assertContains('Subject: My Subject', $mock->header);
  145. $this->assertContains('To: recipient1@example.com', $mock->header);
  146. $this->assertContains('Cc: Example no. 1 for cc <recipient1_cc@example.com>', $mock->header);
  147. }
  148. /**
  149. * Test sending in arrays of recipients
  150. */
  151. public function testArrayRecipients()
  152. {
  153. $mail = new Zend_Mail();
  154. $res = $mail->setBodyText('Test #2');
  155. $mail->setFrom('eli@example.com', 'test Mail User');
  156. $mail->setSubject('Subject #2');
  157. $mail->addTo(array('heather@example.com', 'Ramsey White' => 'ramsey@example.com'));
  158. $mail->addCc(array('keith@example.com', 'Cal Evans' => 'cal@example.com'));
  159. $mail->addBcc(array('ralph@example.com', 'matthew@example.com'));
  160. $mock = new Zend_Mail_Transport_Mock();
  161. $mail->send($mock);
  162. $this->assertTrue($mock->called);
  163. $this->assertEquals('eli@example.com', $mock->from);
  164. $this->assertContains('heather@example.com', $mock->recipients);
  165. $this->assertContains('ramsey@example.com', $mock->recipients);
  166. $this->assertContains('ralph@example.com', $mock->recipients);
  167. $this->assertContains('matthew@example.com', $mock->recipients);
  168. $this->assertContains('keith@example.com', $mock->recipients);
  169. $this->assertContains('cal@example.com', $mock->recipients);
  170. $this->assertContains('Test #2', $mock->body);
  171. $this->assertContains('From: test Mail User <eli@example.com>', $mock->header);
  172. $this->assertContains('Subject: Subject #2', $mock->header);
  173. $this->assertContains('To: heather@example.com', $mock->header);
  174. $this->assertContains('Ramsey White <ramsey@example.com>', $mock->header);
  175. $this->assertContains('Cal Evans <cal@example.com>', $mock->header);
  176. }
  177. /**
  178. * Check if Header Fields are encoded correctly and if
  179. * header injection is prevented.
  180. */
  181. public function testHeaderEncoding()
  182. {
  183. $mail = new Zend_Mail("UTF-8");
  184. $mail->setBodyText('My Nice Test Text');
  185. // try header injection:
  186. $mail->addTo("testmail@example.com\nCc:foobar@example.com");
  187. $mail->addHeader('X-MyTest', "Test\nCc:foobar2@example.com", true);
  188. // try special Chars in Header Fields:
  189. $mail->setFrom('mymail@example.com', "\xC6\x98\xC6\x90\xC3\xA4\xC4\xB8");
  190. $mail->addTo('testmail2@example.com', "\xC4\xA7\xC4\xAF\xC7\xAB");
  191. $mail->addCc('testmail3@example.com', "\xC7\xB6\xC7\xB7");
  192. $mail->setSubject("\xC7\xB1\xC7\xAE");
  193. $mail->addHeader('X-MyTest', "Test-\xC7\xB1", true);
  194. $mock = new Zend_Mail_Transport_Mock();
  195. $mail->send($mock);
  196. $this->assertTrue($mock->called);
  197. $this->assertContains(
  198. 'From: =?UTF-8?Q?=C6=98=C6=90=C3=A4=C4=B8?=',
  199. $mock->header,
  200. "From: Header was encoded unexpectedly."
  201. );
  202. $this->assertContains(
  203. "Cc:foobar@example.com",
  204. $mock->header
  205. );
  206. $this->assertNotContains(
  207. "\nCc:foobar@example.com",
  208. $mock->header,
  209. "Injection into From: header is possible."
  210. );
  211. $this->assertContains(
  212. '=?UTF-8?Q?=C4=A7=C4=AF=C7=AB?= <testmail2@example.com>',
  213. $mock->header
  214. );
  215. $this->assertContains(
  216. 'Cc: =?UTF-8?Q?=C7=B6=C7=B7?= <testmail3@example.com>',
  217. $mock->header
  218. );
  219. $this->assertContains(
  220. 'Subject: =?UTF-8?Q?=C7=B1=C7=AE?=',
  221. $mock->header
  222. );
  223. $this->assertContains(
  224. 'X-MyTest:',
  225. $mock->header
  226. );
  227. $this->assertNotContains(
  228. "\nCc:foobar2@example.com",
  229. $mock->header
  230. );
  231. $this->assertContains(
  232. '=?UTF-8?Q?Test-=C7=B1?=',
  233. $mock->header
  234. );
  235. }
  236. /**
  237. * @group ZF-7799
  238. */
  239. public function testHeaderSendMailTransportHaveNoRightTrim()
  240. {
  241. $mail = new Zend_Mail("UTF-8");
  242. $mail->setBodyText('My Nice Test Text');
  243. $mail->addTo("foobar@example.com");
  244. $mail->setSubject("hello world!");
  245. $transportMock = new Zend_Mail_Transport_Sendmail_Mock();
  246. $mail->send($transportMock);
  247. $this->assertEquals($transportMock->header, rtrim($transportMock->header));
  248. }
  249. /**
  250. * Check if Header Fields are stripped accordingly in sendmail transport;
  251. * also check for header injection
  252. * @todo Determine why this fails in Windows (testmail3@example.com example)
  253. */
  254. public function testHeaderEncoding2()
  255. {
  256. $mail = new Zend_Mail("UTF-8");
  257. $mail->setBodyText('My Nice Test Text');
  258. // try header injection:
  259. $mail->addTo("testmail@example.com\nCc:foobar@example.com");
  260. $mail->addHeader('X-MyTest', "Test\nCc:foobar2@example.com", true);
  261. // try special Chars in Header Fields:
  262. $mail->setFrom('mymail@example.com', "\xC6\x98\xC6\x90\xC3\xA4\xC4\xB8");
  263. $mail->addTo('testmail2@example.com', "\xC4\xA7\xC4\xAF\xC7\xAB");
  264. $mail->addCc('testmail3@example.com', "\xC7\xB6\xC7\xB7");
  265. $mail->setSubject("\xC7\xB1\xC7\xAE");
  266. $mail->addHeader('X-MyTest', "Test-\xC7\xB1", true);
  267. $mock = new Zend_Mail_Transport_Sendmail_Mock();
  268. $mail->send($mock);
  269. $this->assertTrue($mock->called);
  270. $this->assertContains(
  271. 'From: =?UTF-8?Q?=C6=98=C6=90=C3=A4=C4=B8?=',
  272. $mock->header,
  273. "From: Header was encoded unexpectedly."
  274. );
  275. $this->assertNotContains(
  276. "\nCc:foobar@example.com",
  277. $mock->header,
  278. "Injection into From: header is possible."
  279. );
  280. // To is done by mail() not in headers
  281. $this->assertNotContains(
  282. 'To: =?UTF-8?Q?=C4=A7=C4=AF=C7=AB?= <testmail2@example.com>',
  283. $mock->header
  284. );
  285. $this->assertContains(
  286. 'Cc: =?UTF-8?Q?=C7=B6=C7=B7?= <testmail3@example.com>',
  287. $mock->header
  288. );
  289. // Subject is done by mail() not in headers
  290. $this->assertNotContains(
  291. 'Subject: =?UTF-8?Q?=C7=B1=C7=AE?=',
  292. $mock->header
  293. );
  294. $this->assertContains(
  295. 'X-MyTest:',
  296. $mock->header
  297. );
  298. $this->assertNotContains(
  299. "\nCc:foobar2@example.com",
  300. $mock->header
  301. );
  302. $this->assertContains(
  303. '=?UTF-8?Q?Test-=C7=B1?=',
  304. $mock->header
  305. );
  306. }
  307. /**
  308. * Check if Mails with HTML and Text Body are generated correctly.
  309. *
  310. */
  311. public function testMultipartAlternative()
  312. {
  313. $mail = new Zend_Mail();
  314. $mail->setBodyText('My Nice Test Text');
  315. $mail->setBodyHtml('My Nice <b>Test</b> Text');
  316. $mail->addTo('testmail@example.com', 'Test Recipient');
  317. $mail->setFrom('mymail@example.com', 'Test Sender');
  318. $mail->setSubject('Test: Alternate Mail with Zend_Mail');
  319. $mock = new Zend_Mail_Transport_Mock();
  320. $mail->send($mock);
  321. // check headers
  322. $this->assertTrue($mock->called);
  323. $this->assertContains('multipart/alternative', $mock->header);
  324. $boundary = $mock->boundary;
  325. $this->assertContains('boundary="' . $boundary . '"', $mock->header);
  326. $this->assertContains('MIME-Version: 1.0', $mock->header);
  327. // check body
  328. // search for first boundary
  329. $p1 = strpos($mock->body, "--$boundary\n");
  330. $this->assertNotNull($p1, $boundary . ': ' . $mock->body);
  331. // cut out first (Text) part
  332. $start1 = $p1 + 3 + strlen($boundary);
  333. $p2 = strpos($mock->body, "--$boundary\n", $start1);
  334. $this->assertNotNull($p2);
  335. $partBody1 = substr($mock->body, $start1, ($p2 - $start1));
  336. $this->assertContains('Content-Type: text/plain', $partBody1);
  337. $this->assertContains('My Nice Test Text', $partBody1);
  338. // check second (HTML) part
  339. // search for end boundary
  340. $start2 = $p2 + 3 + strlen($boundary);
  341. $p3 = strpos($mock->body, "--$boundary--");
  342. $this->assertNotNull($p3);
  343. $partBody2 = substr($mock->body, $start2, ($p3 - $start2));
  344. $this->assertContains('Content-Type: text/html', $partBody2);
  345. $this->assertContains('My Nice <b>Test</b> Text', $partBody2);
  346. }
  347. /**
  348. * check if attachment handling works
  349. *
  350. */
  351. public function testAttachment()
  352. {
  353. $mail = new Zend_Mail();
  354. $mail->setBodyText('My Nice Test Text');
  355. $mail->addTo('testmail@example.com', 'Test Recipient');
  356. $mail->setFrom('mymail@example.com', 'Test Sender');
  357. $mail->setSubject('Test: Attachment Test with Zend_Mail');
  358. $at = $mail->createAttachment('abcdefghijklmnopqrstuvexyz');
  359. $at->type = 'image/gif';
  360. $at->id = 12;
  361. $at->filename = 'test.gif';
  362. $mock = new Zend_Mail_Transport_Mock();
  363. $mail->send($mock);
  364. // now check what was generated by Zend_Mail.
  365. // first the mail headers:
  366. $this->assertContains('Content-Type: multipart/mixed', $mock->header, $mock->header);
  367. $boundary = $mock->boundary;
  368. $this->assertContains('boundary="' . $boundary . '"', $mock->header);
  369. $this->assertContains('MIME-Version: 1.0', $mock->header);
  370. // check body
  371. // search for first boundary
  372. $p1 = strpos($mock->body, "--$boundary\n");
  373. $this->assertNotNull($p1);
  374. // cut out first (Text) part
  375. $start1 = $p1 + 3 + strlen($boundary);
  376. $p2 = strpos($mock->body, "--$boundary\n", $start1);
  377. $this->assertNotNull($p2);
  378. $partBody1 = substr($mock->body, $start1, ($p2 - $start1));
  379. $this->assertContains('Content-Type: text/plain', $partBody1);
  380. $this->assertContains('My Nice Test Text', $partBody1);
  381. // check second (HTML) part
  382. // search for end boundary
  383. $start2 = $p2 + 3 + strlen($boundary);
  384. $p3 = strpos($mock->body, "--$boundary--");
  385. $this->assertNotNull($p3);
  386. $partBody2 = substr($mock->body, $start2, ($p3 - $start2));
  387. $this->assertContains('Content-Type: image/gif', $partBody2);
  388. $this->assertContains('Content-Transfer-Encoding: base64', $partBody2);
  389. $this->assertContains('Content-ID: <12>', $partBody2);
  390. }
  391. /**
  392. * Check if Mails with HTML and Text Body are generated correctly.
  393. *
  394. */
  395. public function testMultipartAlternativePlusAttachment()
  396. {
  397. $mail = new Zend_Mail();
  398. $mail->setBodyText('My Nice Test Text');
  399. $mail->setBodyHtml('My Nice <b>Test</b> Text');
  400. $mail->addTo('testmail@example.com', 'Test Recipient');
  401. $mail->setFrom('mymail@example.com', 'Test Sender');
  402. $mail->setSubject('Test: Alternate Mail with Zend_Mail');
  403. $at = $mail->createAttachment('abcdefghijklmnopqrstuvexyz');
  404. $at->type = 'image/gif';
  405. $at->id = 12;
  406. $at->filename = 'test.gif';
  407. $mock = new Zend_Mail_Transport_Mock();
  408. $mail->send($mock);
  409. // check headers
  410. $this->assertTrue($mock->called);
  411. $this->assertContains('multipart/mixed', $mock->header);
  412. $boundary = $mock->boundary;
  413. $this->assertContains('boundary="' . $boundary . '"', $mock->header);
  414. $this->assertContains('MIME-Version: 1.0', $mock->header);
  415. // check body
  416. // search for first boundary
  417. $p1 = strpos($mock->body, "--$boundary\n");
  418. $this->assertNotNull($p1);
  419. // cut out first (multipart/alternative) part
  420. $start1 = $p1 + 3 + strlen($boundary);
  421. $p2 = strpos($mock->body, "--$boundary\n", $start1);
  422. $this->assertNotNull($p2);
  423. $partBody1 = substr($mock->body, $start1, ($p2 - $start1));
  424. $this->assertContains('Content-Type: multipart/alternative', $partBody1);
  425. $this->assertContains('Content-Type: text/plain', $partBody1);
  426. $this->assertContains('Content-Type: text/html', $partBody1);
  427. $this->assertContains('My Nice Test Text', $partBody1);
  428. $this->assertContains('My Nice <b>Test</b> Text', $partBody1);
  429. // check second (image) part
  430. // search for end boundary
  431. $start2 = $p2 + 3 + strlen($boundary);
  432. $p3 = strpos($mock->body, "--$boundary--");
  433. $this->assertNotNull($p3);
  434. $partBody2 = substr($mock->body, $start2, ($p3 - $start2));
  435. $this->assertContains('Content-Type: image/gif', $partBody2);
  436. $this->assertContains('Content-Transfer-Encoding: base64', $partBody2);
  437. $this->assertContains('Content-ID: <12>', $partBody2);
  438. }
  439. public function testReturnPath()
  440. {
  441. $mail = new Zend_Mail();
  442. $res = $mail->setBodyText('This is a test.');
  443. $mail->setFrom('testmail@example.com', 'test Mail User');
  444. $mail->setSubject('My Subject');
  445. $mail->addTo('recipient1@example.com');
  446. $mail->addTo('recipient2@example.com');
  447. $mail->addBcc('recipient1_bcc@example.com');
  448. $mail->addBcc('recipient2_bcc@example.com');
  449. $mail->addCc('recipient1_cc@example.com', 'Example no. 1 for cc');
  450. $mail->addCc('recipient2_cc@example.com', 'Example no. 2 for cc');
  451. // First example: from and return-path should be equal
  452. $mock = new Zend_Mail_Transport_Mock();
  453. $mail->send($mock);
  454. $this->assertTrue($mock->called);
  455. $this->assertEquals($mail->getFrom(), $mock->returnPath);
  456. // Second example: from and return-path should not be equal
  457. $mail->setReturnPath('sender2@example.com');
  458. $mock = new Zend_Mail_Transport_Mock();
  459. $mail->send($mock);
  460. $this->assertTrue($mock->called);
  461. $this->assertNotEquals($mail->getFrom(), $mock->returnPath);
  462. $this->assertEquals($mail->getReturnPath(), $mock->returnPath);
  463. $this->assertNotEquals($mock->returnPath, $mock->from);
  464. }
  465. public function testNoBody()
  466. {
  467. $mail = new Zend_Mail();
  468. $mail->setFrom('testmail@example.com', 'test Mail User');
  469. $mail->setSubject('My Subject');
  470. $mail->addTo('recipient1@example.com');
  471. // First example: from and return-path should be equal
  472. $mock = new Zend_Mail_Transport_Mock();
  473. try {
  474. $mail->send($mock);
  475. $this->assertTrue($mock->called);
  476. } catch (Exception $e) {
  477. // success
  478. $this->assertContains('No body specified', $e->getMessage());
  479. }
  480. }
  481. /**
  482. * Helper method for {@link testZf928ToAndBccHeadersShouldNotMix()}; extracts individual header lines
  483. *
  484. * @param Zend_Mail_Transport_Abstract $mock
  485. * @param string $type
  486. * @return string
  487. */
  488. protected function _getHeader(Zend_Mail_Transport_Abstract $mock, $type = 'To')
  489. {
  490. $headers = str_replace("\r\n", "\n", $mock->header);
  491. $headers = explode("\n", $mock->header);
  492. $return = '';
  493. foreach ($headers as $header) {
  494. if (!empty($return)) {
  495. // Check for header continuation
  496. if (!preg_match('/^[a-z-]+:/i', $header)) {
  497. $return .= "\r\n" . $header;
  498. continue;
  499. } else {
  500. break;
  501. }
  502. }
  503. if (preg_match('/^' . $type . ': /', $header)) {
  504. $return = $header;
  505. }
  506. }
  507. return $return;
  508. }
  509. public function testZf928ToAndBccHeadersShouldNotMix()
  510. {
  511. $mail = new Zend_Mail();
  512. $mail->setSubject('my subject');
  513. $mail->setBodyText('my body');
  514. $mail->setFrom('info@onlime.ch');
  515. $mail->addTo('to.address@email.com');
  516. $mail->addBcc('first.bcc@email.com');
  517. $mail->addBcc('second.bcc@email.com');
  518. // test with generic transport
  519. $mock = new Zend_Mail_Transport_Mock();
  520. $mail->send($mock);
  521. $to = $this->_getHeader($mock);
  522. $bcc = $this->_getHeader($mock, 'Bcc');
  523. $this->assertContains('to.address@email.com', $to, $to);
  524. $this->assertNotContains('second.bcc@email.com', $to, $bcc);
  525. // test with sendmail-like transport
  526. $mock = new Zend_Mail_Transport_Sendmail_Mock();
  527. $mail->send($mock);
  528. $to = $this->_getHeader($mock);
  529. $bcc = $this->_getHeader($mock, 'Bcc');
  530. // Remove the following line due to fixes by Simon
  531. // $this->assertNotContains('to.address@email.com', $to, $mock->header);
  532. $this->assertNotContains('second.bcc@email.com', $to, $bcc);
  533. }
  534. public function testZf927BlankLinesShouldPersist()
  535. {
  536. $mail = new Zend_Mail();
  537. $mail->setSubject('my subject');
  538. $mail->setBodyText("my body\r\n\r\n...after two newlines");
  539. $mail->setFrom('test@email.com');
  540. $mail->addTo('test@email.com');
  541. // test with generic transport
  542. $mock = new Zend_Mail_Transport_Sendmail_Mock();
  543. $mail->send($mock);
  544. $body = quoted_printable_decode($mock->body);
  545. $this->assertContains("\r\n\r\n...after", $body, $body);
  546. }
  547. public function testGetJustBodyText()
  548. {
  549. $text = "my body\r\n\r\n...after two newlines";
  550. $mail = new Zend_Mail();
  551. $mail->setBodyText($text);
  552. $this->assertContains('my body', $mail->getBodyText(true));
  553. $this->assertContains('after two newlines', $mail->getBodyText(true));
  554. }
  555. public function testGetJustBodyHtml()
  556. {
  557. $text = "<html><head></head><body><p>Some body text</p></body></html>";
  558. $mail = new Zend_Mail();
  559. $mail->setBodyHtml($text);
  560. $this->assertContains('Some body text', $mail->getBodyHtml(true));
  561. }
  562. public function testTypeAccessor()
  563. {
  564. $mail = new Zend_Mail();
  565. $this->assertNull($mail->getType());
  566. $mail->setType(Zend_Mime::MULTIPART_ALTERNATIVE);
  567. $this->assertEquals(Zend_Mime::MULTIPART_ALTERNATIVE, $mail->getType());
  568. $mail->setType(Zend_Mime::MULTIPART_RELATED);
  569. $this->assertEquals(Zend_Mime::MULTIPART_RELATED, $mail->getType());
  570. try {
  571. $mail->setType('text/plain');
  572. $this->fail('Invalid Zend_Mime type should throw an exception');
  573. } catch (Exception $e) {
  574. }
  575. }
  576. public function testDateSet()
  577. {
  578. $mail = new Zend_Mail();
  579. $res = $mail->setBodyText('Date Test');
  580. $mail->setFrom('testmail@example.com', 'test Mail User');
  581. $mail->setSubject('Date Test');
  582. $mail->addTo('recipient@example.com');
  583. $mock = new Zend_Mail_Transport_Mock();
  584. $mail->send($mock);
  585. $this->assertTrue($mock->called);
  586. $this->assertTrue(isset($mock->headers['Date']));
  587. $this->assertTrue(isset($mock->headers['Date'][0]));
  588. $this->assertTrue(strlen($mock->headers['Date'][0]) > 0);
  589. }
  590. public function testSetDateInt()
  591. {
  592. $mail = new Zend_Mail();
  593. $res = $mail->setBodyText('Date Test');
  594. $mail->setFrom('testmail@example.com', 'test Mail User');
  595. $mail->setSubject('Date Test');
  596. $mail->addTo('recipient@example.com');
  597. $mail->setDate(362656800);
  598. $mock = new Zend_Mail_Transport_Mock();
  599. $mail->send($mock);
  600. $this->assertTrue($mock->called);
  601. $this->assertTrue(strpos(implode('', $mock->headers['Date']), 'Mon, 29 Jun 1981') === 0);
  602. }
  603. public function testSetDateString()
  604. {
  605. $mail = new Zend_Mail();
  606. $res = $mail->setBodyText('Date Test');
  607. $mail->setFrom('testmail@example.com', 'test Mail User');
  608. $mail->setSubject('Date Test');
  609. $mail->addTo('recipient@example.com');
  610. $mail->setDate('1981-06-29T12:00:00');
  611. $mock = new Zend_Mail_Transport_Mock();
  612. $mail->send($mock);
  613. $this->assertTrue($mock->called);
  614. $this->assertTrue(strpos(implode('', $mock->headers['Date']), 'Mon, 29 Jun 1981') === 0);
  615. }
  616. public function testSetDateObject()
  617. {
  618. $mail = new Zend_Mail();
  619. $res = $mail->setBodyText('Date Test');
  620. $mail->setFrom('testmail@example.com', 'test Mail User');
  621. $mail->setSubject('Date Test');
  622. $mail->addTo('recipient@example.com');
  623. $mail->setDate(new Zend_Date('1981-06-29T12:00:00', Zend_Date::ISO_8601));
  624. $mock = new Zend_Mail_Transport_Mock();
  625. $mail->send($mock);
  626. $this->assertTrue($mock->called);
  627. $this->assertTrue(strpos(implode('', $mock->headers['Date']), 'Mon, 29 Jun 1981') === 0);
  628. }
  629. public function testSetDateInvalidString()
  630. {
  631. $mail = new Zend_Mail();
  632. try {
  633. $mail->setDate('invalid date');
  634. $this->fail('Invalid date should throw an exception');
  635. } catch (Exception $e) {
  636. }
  637. }
  638. public function testSetDateInvalidType()
  639. {
  640. $mail = new Zend_Mail();
  641. try {
  642. $mail->setDate(true);
  643. $this->fail('Invalid date should throw an exception');
  644. } catch (Exception $e) {
  645. }
  646. }
  647. public function testSetDateInvalidObject()
  648. {
  649. $mail = new Zend_Mail();
  650. try {
  651. $mail->setDate($mail);
  652. $this->fail('Invalid date should throw an exception');
  653. } catch (Exception $e) {
  654. }
  655. }
  656. public function testSetDateTwice()
  657. {
  658. $mail = new Zend_Mail();
  659. $mail->setDate();
  660. try {
  661. $mail->setDate(123456789);
  662. $this->fail('setting date twice should throw an exception');
  663. } catch (Exception $e) {
  664. }
  665. }
  666. /**
  667. * @group ZF-6872
  668. */
  669. public function testSetReplyTo()
  670. {
  671. $mail = new Zend_Mail('UTF-8');
  672. $mail->setReplyTo("foo@zend.com", "\xe2\x82\xa0!");
  673. $headers = $mail->getHeaders();
  674. $this->assertEquals("=?UTF-8?Q?=E2=82=A0!?= <foo@zend.com>", $headers["Reply-To"][0]);
  675. }
  676. /**
  677. * @group ZF-1688
  678. * @group ZF-2559
  679. */
  680. public function testSetHeaderEncoding()
  681. {
  682. $mail = new Zend_Mail();
  683. $this->assertEquals(Zend_Mime::ENCODING_QUOTEDPRINTABLE, $mail->getHeaderEncoding());
  684. $mail->setHeaderEncoding(Zend_Mime::ENCODING_BASE64);
  685. $this->assertEquals(Zend_Mime::ENCODING_BASE64, $mail->getHeaderEncoding());
  686. }
  687. /**
  688. * @group ZF-1688
  689. * @dataProvider dataSubjects
  690. */
  691. public function testIfLongSubjectsHaveCorrectLineBreaksAndEncodingMarks($subject)
  692. {
  693. $mail = new Zend_Mail("UTF-8");
  694. $mail->setSubject($subject);
  695. $headers = $mail->getHeaders();
  696. $this->assertMailHeaderConformsToRfc($headers['Subject'][0]);
  697. }
  698. /**
  699. * @group ZF-7702
  700. */
  701. public function testReplyToIsNoRecipient() {
  702. $mail = new Zend_Mail();
  703. $mail->setReplyTo('foo@example.com','foobar');
  704. $this->assertEquals(0, count($mail->getRecipients()));
  705. }
  706. public function testGetReplyToReturnsReplyTo() {
  707. $mail = new Zend_Mail();
  708. $mail->setReplyTo('foo@example.com');
  709. $this->assertEquals('foo@example.com',$mail->getReplyTo());
  710. }
  711. /**
  712. * @expectedException Zend_Mail_Exception
  713. */
  714. public function testReplyToCantBeSetTwice() {
  715. $mail = new Zend_Mail();
  716. $mail->setReplyTo('user@example.com');
  717. $mail->setReplyTo('user2@example.com');
  718. }
  719. public static function dataSubjects()
  720. {
  721. return array(
  722. array("Simple Ascii Subject"),
  723. array("Subject with US Specialchars: &%$/()"),
  724. array("Gimme more \xe2\x82\xa0!"),
  725. array("This is \xc3\xa4n germ\xc3\xa4n multiline s\xc3\xbcbject with rand\xc3\xb6m \xc3\xbcml\xc3\xa4uts."),
  726. array("Alle meine Entchen schwimmen in dem See, schwimmen in dem See, K\xc3\xb6pfchen in das Wasser, Schw\xc3\xa4nzchen in die H\xc3\xb6h!"),
  727. array("\xc3\xa4\xc3\xa4xxxxx\xc3\xa4\xc3\xa4\xc3\xa4\xc3\xa4\xc3\xa4\xc3\xa4\xc3\xa4"),
  728. array("\xd0\x90\xd0\x91\xd0\x92\xd0\x93\xd0\x94\xd0\x95 \xd0\x96\xd0\x97\xd0\x98\xd0\x99 \xd0\x9a\xd0\x9b\xd0\x9c\xd0\x9d"),
  729. array("Ich. Denke. Also. Bin. Ich! (Ein \xc3\xbcml\xc3\xa4\xc3\xbctautomat!)"),
  730. );
  731. }
  732. /**
  733. * Assertion that checks if a given mailing header string is RFC conform.
  734. *
  735. * @param string $header
  736. * @return void
  737. */
  738. protected function assertMailHeaderConformsToRfc($header)
  739. {
  740. $this->numAssertions++;
  741. $parts = explode(Zend_Mime::LINEEND, $header);
  742. if(count($parts) > 0) {
  743. for($i = 0; $i < count($parts); $i++) {
  744. if(preg_match('/(=?[a-z0-9-_]+\?[q|b]{1}\?)/i', $parts[$i], $matches)) {
  745. $dce = sprintf("=?%s", $matches[0]);
  746. // Check that Delimiter, Charset, Encoding are at the front of the string
  747. if(substr(trim($parts[$i]), 0, strlen($dce)) != $dce) {
  748. $this->fail(sprintf(
  749. "Header-Part '%s' in line '%d' has missing or malformated delimiter, charset, encoding information.",
  750. $parts[$i],
  751. $i+1
  752. ));
  753. }
  754. // check that the encoded word is not too long.);
  755. // this is only some kind of suggestion by the standard, in PHP its hard to hold it, so we do not enforce it here.
  756. /*if(strlen($parts[$i]) > 75) {
  757. $this->fail(sprintf(
  758. "Each encoded-word is only allowed to be 75 chars long, but line %d is %s chars long: %s",
  759. $i+1,
  760. strlen($parts[$i]),
  761. $parts[$i]
  762. ));
  763. }*/
  764. // Check that the end-delmiter ?= is correctly placed
  765. if(substr(trim($parts[$i]), -2, 2) != "?=") {
  766. $this->fail(sprintf(
  767. "Lines with an encoded-word have to end in ?=, but line %d does not: %s",
  768. $i+1,
  769. substr(trim($parts[$i]), -2, 2)
  770. ));
  771. }
  772. // Check that only one encoded-word can be found per line.
  773. if(substr_count($parts[$i], "=?") != 1) {
  774. $this->fail(sprintf(
  775. "Only one encoded-word is allowed per line in the header. It seems line %d contains more: %s",
  776. $i+1,
  777. $parts[$i]
  778. ));
  779. }
  780. // Check that the encoded-text only contains US-ASCII chars, and no space
  781. $encodedText = substr(trim($parts[$i]), strlen($dce), -2);
  782. if(preg_match('/([\s]+)/', $encodedText)) {
  783. $this->fail(sprintf(
  784. "No whitespace characters allowed in encoded-text of line %d: %s",
  785. $i+1,
  786. $parts[$i]
  787. ));
  788. }
  789. for($i = 0; $i < strlen($encodedText); $i++) {
  790. if(ord($encodedText[$i]) > 127) {
  791. $this->fail(sprintf(
  792. "No non US-ASCII characters allowed, but line %d has them: %s",
  793. $i+1,
  794. $parts[$i]
  795. ));
  796. }
  797. }
  798. } else if(Zend_Mime::isPrintable($parts[$i]) == false) {
  799. $this->fail(sprintf(
  800. "Encoded-word in line %d contains non printable characters.",
  801. $i+1
  802. ));
  803. }
  804. }
  805. }
  806. }
  807. }