Просмотр файла main_files/phpmailer/test/phpmailerTest.php

Размер файла: 75.65Kb
  1. <?php
  2. /**
  3. * PHPMailer - PHP email transport unit tests
  4. * Requires PHPUnit 3.3 or later.
  5. *
  6. * PHP version 5.0.0
  7. *
  8. * @package PHPMailer
  9. * @author Andy Prevost
  10. * @author Marcus Bointon <phpmailer@synchromedia.co.uk>
  11. * @copyright 2004 - 2009 Andy Prevost
  12. * @copyright 2010 Marcus Bointon
  13. * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  14. */
  15.  
  16. require_once '../PHPMailerAutoload.php';
  17.  
  18. /**
  19. * PHPMailer - PHP email transport unit test class
  20. * Performs authentication tests
  21. */
  22. class PHPMailerTest extends PHPUnit_Framework_TestCase
  23. {
  24. /**
  25. * Holds the default phpmailer instance.
  26. * @private
  27. * @var PHPMailer
  28. */
  29. public $Mail;
  30.  
  31. /**
  32. * Holds the SMTP mail host.
  33. * @public
  34. * @var string
  35. */
  36. public $Host = '';
  37.  
  38. /**
  39. * Holds the change log.
  40. * @private
  41. * @var string[]
  42. */
  43. public $ChangeLog = array();
  44.  
  45. /**
  46. * Holds the note log.
  47. * @private
  48. * @var string[]
  49. */
  50. public $NoteLog = array();
  51.  
  52. /**
  53. * Default include path
  54. * @var string
  55. */
  56. public $INCLUDE_DIR = '../';
  57.  
  58. /**
  59. * PIDs of any processes we need to kill
  60. * @var array
  61. * @access private
  62. */
  63. private $pids = array();
  64.  
  65. /**
  66. * Run before each test is started.
  67. */
  68. public function setUp()
  69. {
  70. if (file_exists('./testbootstrap.php')) {
  71. include './testbootstrap.php'; //Overrides go in here
  72. }
  73. $this->Mail = new PHPMailer;
  74. $this->Mail->SMTPDebug = 3; //Full debug output
  75. $this->Mail->Priority = 3;
  76. $this->Mail->Encoding = '8bit';
  77. $this->Mail->CharSet = 'iso-8859-1';
  78. if (array_key_exists('mail_from', $_REQUEST)) {
  79. $this->Mail->From = $_REQUEST['mail_from'];
  80. } else {
  81. $this->Mail->From = 'unit_test@phpmailer.example.com';
  82. }
  83. $this->Mail->FromName = 'Unit Tester';
  84. $this->Mail->Sender = '';
  85. $this->Mail->Subject = 'Unit Test';
  86. $this->Mail->Body = '';
  87. $this->Mail->AltBody = '';
  88. $this->Mail->WordWrap = 0;
  89. if (array_key_exists('mail_host', $_REQUEST)) {
  90. $this->Mail->Host = $_REQUEST['mail_host'];
  91. } else {
  92. $this->Mail->Host = 'mail.example.com';
  93. }
  94. if (array_key_exists('mail_port', $_REQUEST)) {
  95. $this->Mail->Port = $_REQUEST['mail_port'];
  96. } else {
  97. $this->Mail->Port = 25;
  98. }
  99. $this->Mail->Helo = 'localhost.localdomain';
  100. $this->Mail->SMTPAuth = false;
  101. $this->Mail->Username = '';
  102. $this->Mail->Password = '';
  103. $this->Mail->PluginDir = $this->INCLUDE_DIR;
  104. $this->Mail->addReplyTo('no_reply@phpmailer.example.com', 'Reply Guy');
  105. $this->Mail->Sender = 'unit_test@phpmailer.example.com';
  106. if (strlen($this->Mail->Host) > 0) {
  107. $this->Mail->Mailer = 'smtp';
  108. } else {
  109. $this->Mail->Mailer = 'mail';
  110. }
  111. if (array_key_exists('mail_to', $_REQUEST)) {
  112. $this->setAddress($_REQUEST['mail_to'], 'Test User', 'to');
  113. }
  114. if (array_key_exists('mail_cc', $_REQUEST) and strlen($_REQUEST['mail_cc']) > 0) {
  115. $this->setAddress($_REQUEST['mail_cc'], 'Carbon User', 'cc');
  116. }
  117. }
  118.  
  119. /**
  120. * Run after each test is completed.
  121. */
  122. public function tearDown()
  123. {
  124. // Clean global variables
  125. $this->Mail = null;
  126. $this->ChangeLog = array();
  127. $this->NoteLog = array();
  128.  
  129. foreach ($this->pids as $pid) {
  130. $p = escapeshellarg($pid);
  131. shell_exec("ps $p && kill -TERM $p");
  132. }
  133. }
  134.  
  135.  
  136. /**
  137. * Build the body of the message in the appropriate format.
  138. *
  139. * @private
  140. * @return void
  141. */
  142. public function buildBody()
  143. {
  144. $this->checkChanges();
  145.  
  146. // Determine line endings for message
  147. if ($this->Mail->ContentType == 'text/html' || strlen($this->Mail->AltBody) > 0) {
  148. $eol = "<br>\r\n";
  149. $bullet_start = '<li>';
  150. $bullet_end = "</li>\r\n";
  151. $list_start = "<ul>\r\n";
  152. $list_end = "</ul>\r\n";
  153. } else {
  154. $eol = "\r\n";
  155. $bullet_start = ' - ';
  156. $bullet_end = "\r\n";
  157. $list_start = '';
  158. $list_end = '';
  159. }
  160.  
  161. $ReportBody = '';
  162.  
  163. $ReportBody .= '---------------------' . $eol;
  164. $ReportBody .= 'Unit Test Information' . $eol;
  165. $ReportBody .= '---------------------' . $eol;
  166. $ReportBody .= 'phpmailer version: ' . $this->Mail->Version . $eol;
  167. $ReportBody .= 'Content Type: ' . $this->Mail->ContentType . $eol;
  168. $ReportBody .= 'CharSet: ' . $this->Mail->CharSet . $eol;
  169.  
  170. if (strlen($this->Mail->Host) > 0) {
  171. $ReportBody .= 'Host: ' . $this->Mail->Host . $eol;
  172. }
  173.  
  174. // If attachments then create an attachment list
  175. $attachments = $this->Mail->getAttachments();
  176. if (count($attachments) > 0) {
  177. $ReportBody .= 'Attachments:' . $eol;
  178. $ReportBody .= $list_start;
  179. foreach ($attachments as $attachment) {
  180. $ReportBody .= $bullet_start . 'Name: ' . $attachment[1] . ', ';
  181. $ReportBody .= 'Encoding: ' . $attachment[3] . ', ';
  182. $ReportBody .= 'Type: ' . $attachment[4] . $bullet_end;
  183. }
  184. $ReportBody .= $list_end . $eol;
  185. }
  186.  
  187. // If there are changes then list them
  188. if (count($this->ChangeLog) > 0) {
  189. $ReportBody .= 'Changes' . $eol;
  190. $ReportBody .= '-------' . $eol;
  191.  
  192. $ReportBody .= $list_start;
  193. for ($i = 0; $i < count($this->ChangeLog); $i++) {
  194. $ReportBody .= $bullet_start . $this->ChangeLog[$i][0] . ' was changed to [' .
  195. $this->ChangeLog[$i][1] . ']' . $bullet_end;
  196. }
  197. $ReportBody .= $list_end . $eol . $eol;
  198. }
  199.  
  200. // If there are notes then list them
  201. if (count($this->NoteLog) > 0) {
  202. $ReportBody .= 'Notes' . $eol;
  203. $ReportBody .= '-----' . $eol;
  204.  
  205. $ReportBody .= $list_start;
  206. for ($i = 0; $i < count($this->NoteLog); $i++) {
  207. $ReportBody .= $bullet_start . $this->NoteLog[$i] . $bullet_end;
  208. }
  209. $ReportBody .= $list_end;
  210. }
  211.  
  212. // Re-attach the original body
  213. $this->Mail->Body .= $eol . $ReportBody;
  214. }
  215.  
  216. /**
  217. * Check which default settings have been changed for the report.
  218. * @private
  219. * @return void
  220. */
  221. public function checkChanges()
  222. {
  223. if ($this->Mail->Priority != 3) {
  224. $this->addChange('Priority', $this->Mail->Priority);
  225. }
  226. if ($this->Mail->Encoding != '8bit') {
  227. $this->addChange('Encoding', $this->Mail->Encoding);
  228. }
  229. if ($this->Mail->CharSet != 'iso-8859-1') {
  230. $this->addChange('CharSet', $this->Mail->CharSet);
  231. }
  232. if ($this->Mail->Sender != '') {
  233. $this->addChange('Sender', $this->Mail->Sender);
  234. }
  235. if ($this->Mail->WordWrap != 0) {
  236. $this->addChange('WordWrap', $this->Mail->WordWrap);
  237. }
  238. if ($this->Mail->Mailer != 'mail') {
  239. $this->addChange('Mailer', $this->Mail->Mailer);
  240. }
  241. if ($this->Mail->Port != 25) {
  242. $this->addChange('Port', $this->Mail->Port);
  243. }
  244. if ($this->Mail->Helo != 'localhost.localdomain') {
  245. $this->addChange('Helo', $this->Mail->Helo);
  246. }
  247. if ($this->Mail->SMTPAuth) {
  248. $this->addChange('SMTPAuth', 'true');
  249. }
  250. }
  251.  
  252. /**
  253. * Add a changelog entry.
  254. * @access private
  255. * @param string $sName
  256. * @param string $sNewValue
  257. * @return void
  258. */
  259. public function addChange($sName, $sNewValue)
  260. {
  261. $this->ChangeLog[] = array($sName, $sNewValue);
  262. }
  263.  
  264. /**
  265. * Adds a simple note to the message.
  266. * @public
  267. * @param string $sValue
  268. * @return void
  269. */
  270. public function addNote($sValue)
  271. {
  272. $this->NoteLog[] = $sValue;
  273. }
  274.  
  275. /**
  276. * Adds all of the addresses
  277. * @access public
  278. * @param string $sAddress
  279. * @param string $sName
  280. * @param string $sType
  281. * @return boolean
  282. */
  283. public function setAddress($sAddress, $sName = '', $sType = 'to')
  284. {
  285. switch ($sType) {
  286. case 'to':
  287. return $this->Mail->addAddress($sAddress, $sName);
  288. case 'cc':
  289. return $this->Mail->addCC($sAddress, $sName);
  290. case 'bcc':
  291. return $this->Mail->addBCC($sAddress, $sName);
  292. }
  293. return false;
  294. }
  295.  
  296. /**
  297. * Check that we have loaded default test params.
  298. * Pretty much everything will fail due to unset recipient if this is not done.
  299. */
  300. public function testBootstrap()
  301. {
  302. $this->assertTrue(
  303. file_exists('./testbootstrap.php'),
  304. 'Test config params missing - copy testbootstrap.php to testbootstrap-dist.php and change as appropriate'
  305. );
  306. }
  307.  
  308. /**
  309. * Test CRAM-MD5 authentication.
  310. * Needs a connection to a server that supports this auth mechanism, so commented out by default
  311. */
  312. public function testAuthCRAMMD5()
  313. {
  314. $this->Mail->Host = 'hostname';
  315. $this->Mail->Port = 587;
  316. $this->Mail->SMTPAuth = true;
  317. $this->Mail->SMTPSecure = 'tls';
  318. $this->Mail->AuthType = 'CRAM-MD5';
  319. $this->Mail->Username = 'username';
  320. $this->Mail->Password = 'password';
  321. $this->Mail->Body = 'Test body';
  322. $this->Mail->Subject .= ': Auth CRAM-MD5';
  323. $this->Mail->From = 'from@example.com';
  324. $this->Mail->Sender = 'from@example.com';
  325. $this->Mail->clearAllRecipients();
  326. $this->Mail->addAddress('user@example.com');
  327. //$this->assertTrue($this->mail->send(), $this->mail->ErrorInfo);
  328. }
  329.  
  330. /**
  331. * Test email address validation.
  332. * Test addresses obtained from http://isemail.info
  333. * Some failing cases commented out that are apparently up for debate!
  334. */
  335. public function testValidate()
  336. {
  337. $validaddresses = array(
  338. 'first@iana.org',
  339. 'first.last@iana.org',
  340. '1234567890123456789012345678901234567890123456789012345678901234@iana.org',
  341. '"first\"last"@iana.org',
  342. '"first@last"@iana.org',
  343. '"first\last"@iana.org',
  344. 'first.last@[12.34.56.78]',
  345. 'first.last@[IPv6:::12.34.56.78]',
  346. 'first.last@[IPv6:1111:2222:3333::4444:12.34.56.78]',
  347. 'first.last@[IPv6:1111:2222:3333:4444:5555:6666:12.34.56.78]',
  348. 'first.last@[IPv6:::1111:2222:3333:4444:5555:6666]',
  349. 'first.last@[IPv6:1111:2222:3333::4444:5555:6666]',
  350. 'first.last@[IPv6:1111:2222:3333:4444:5555:6666::]',
  351. 'first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888]',
  352. 'first.last@x23456789012345678901234567890123456789012345678901234567890123.iana.org',
  353. 'first.last@3com.com',
  354. 'first.last@123.iana.org',
  355. '"first\last"@iana.org',
  356. 'first.last@[IPv6:1111:2222:3333::4444:5555:12.34.56.78]',
  357. 'first.last@[IPv6:1111:2222:3333::4444:5555:6666:7777]',
  358. 'first.last@example.123',
  359. 'first.last@com',
  360. '"Abc\@def"@iana.org',
  361. '"Fred\ Bloggs"@iana.org',
  362. '"Joe.\Blow"@iana.org',
  363. '"Abc@def"@iana.org',
  364. 'user+mailbox@iana.org',
  365. 'customer/department=shipping@iana.org',
  366. '$A12345@iana.org',
  367. '!def!xyz%abc@iana.org',
  368. '_somename@iana.org',
  369. 'dclo@us.ibm.com',
  370. 'peter.piper@iana.org',
  371. '"Doug \"Ace\" L."@iana.org',
  372. 'test@iana.org',
  373. 'TEST@iana.org',
  374. '1234567890@iana.org',
  375. 'test+test@iana.org',
  376. 'test-test@iana.org',
  377. 't*est@iana.org',
  378. '+1~1+@iana.org',
  379. '{_test_}@iana.org',
  380. '"[[ test ]]"@iana.org',
  381. 'test.test@iana.org',
  382. '"test.test"@iana.org',
  383. 'test."test"@iana.org',
  384. '"test@test"@iana.org',
  385. 'test@123.123.123.x123',
  386. 'test@123.123.123.123',
  387. 'test@[123.123.123.123]',
  388. 'test@example.iana.org',
  389. 'test@example.example.iana.org',
  390. '"test\test"@iana.org',
  391. 'test@example',
  392. '"test\blah"@iana.org',
  393. '"test\blah"@iana.org',
  394. '"test\"blah"@iana.org',
  395. 'customer/department@iana.org',
  396. '_Yosemite.Sam@iana.org',
  397. '~@iana.org',
  398. '"Austin@Powers"@iana.org',
  399. 'Ima.Fool@iana.org',
  400. '"Ima.Fool"@iana.org',
  401. '"Ima Fool"@iana.org',
  402. '"first"."last"@iana.org',
  403. '"first".middle."last"@iana.org',
  404. '"first".last@iana.org',
  405. 'first."last"@iana.org',
  406. '"first"."middle"."last"@iana.org',
  407. '"first.middle"."last"@iana.org',
  408. '"first.middle.last"@iana.org',
  409. '"first..last"@iana.org',
  410. '"first\"last"@iana.org',
  411. 'first."mid\dle"."last"@iana.org',
  412. '"test blah"@iana.org',
  413. '(foo)cal(bar)@(baz)iamcal.com(quux)',
  414. 'cal@iamcal(woo).(yay)com',
  415. 'cal(woo(yay)hoopla)@iamcal.com',
  416. 'cal(foo\@bar)@iamcal.com',
  417. 'cal(foo\)bar)@iamcal.com',
  418. 'first().last@iana.org',
  419. 'pete(his account)@silly.test(his host)',
  420. 'c@(Chris\'s host.)public.example',
  421. 'jdoe@machine(comment). example',
  422. '1234 @ local(blah) .machine .example',
  423. 'first(abc.def).last@iana.org',
  424. 'first(a"bc.def).last@iana.org',
  425. 'first.(")middle.last(")@iana.org',
  426. 'first(abc\(def)@iana.org',
  427. 'first.last@x(1234567890123456789012345678901234567890123456789012345678901234567890).com',
  428. 'a(a(b(c)d(e(f))g)h(i)j)@iana.org',
  429. 'name.lastname@domain.com',
  430. 'a@b',
  431. 'a@bar.com',
  432. 'aaa@[123.123.123.123]',
  433. 'a@bar',
  434. 'a-b@bar.com',
  435. '+@b.c',
  436. '+@b.com',
  437. 'a@b.co-foo.uk',
  438. '"hello my name is"@stutter.com',
  439. '"Test \"Fail\" Ing"@iana.org',
  440. 'valid@about.museum',
  441. 'shaitan@my-domain.thisisminekthx',
  442. 'foobar@192.168.0.1',
  443. '"Joe\Blow"@iana.org',
  444. 'HM2Kinsists@(that comments are allowed)this.is.ok',
  445. 'user%uucp!path@berkeley.edu',
  446. 'first.last @iana.org',
  447. 'cdburgess+!#$%&\'*-/=?+_{}|~test@gmail.com',
  448. 'first.last@[IPv6:::a2:a3:a4:b1:b2:b3:b4]',
  449. 'first.last@[IPv6:a1:a2:a3:a4:b1:b2:b3::]',
  450. 'first.last@[IPv6:::]',
  451. 'first.last@[IPv6:::b4]',
  452. 'first.last@[IPv6:::b3:b4]',
  453. 'first.last@[IPv6:a1::b4]',
  454. 'first.last@[IPv6:a1::]',
  455. 'first.last@[IPv6:a1:a2::]',
  456. 'first.last@[IPv6:0123:4567:89ab:cdef::]',
  457. 'first.last@[IPv6:0123:4567:89ab:CDEF::]',
  458. 'first.last@[IPv6:::a3:a4:b1:ffff:11.22.33.44]',
  459. 'first.last@[IPv6:::a2:a3:a4:b1:ffff:11.22.33.44]',
  460. 'first.last@[IPv6:a1:a2:a3:a4::11.22.33.44]',
  461. 'first.last@[IPv6:a1:a2:a3:a4:b1::11.22.33.44]',
  462. 'first.last@[IPv6:a1::11.22.33.44]',
  463. 'first.last@[IPv6:a1:a2::11.22.33.44]',
  464. 'first.last@[IPv6:0123:4567:89ab:cdef::11.22.33.44]',
  465. 'first.last@[IPv6:0123:4567:89ab:CDEF::11.22.33.44]',
  466. 'first.last@[IPv6:a1::b2:11.22.33.44]',
  467. 'test@test.com',
  468. 'test@xn--example.com',
  469. 'test@example.com'
  470. );
  471. $invalidaddresses = array(
  472. 'first.last@sub.do,com',
  473. 'first\@last@iana.org',
  474. '123456789012345678901234567890123456789012345678901234567890' .
  475. '@12345678901234567890123456789012345678901234 [...]',
  476. 'first.last',
  477. '12345678901234567890123456789012345678901234567890123456789012345@iana.org',
  478. '.first.last@iana.org',
  479. 'first.last.@iana.org',
  480. 'first..last@iana.org',
  481. '"first"last"@iana.org',
  482. '"""@iana.org',
  483. '"\"@iana.org',
  484. //'""@iana.org',
  485. 'first\@last@iana.org',
  486. 'first.last@',
  487. 'x@x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.' .
  488. 'x23456789.x23456789.x23456789.x23 [...]',
  489. 'first.last@[.12.34.56.78]',
  490. 'first.last@[12.34.56.789]',
  491. 'first.last@[::12.34.56.78]',
  492. 'first.last@[IPv5:::12.34.56.78]',
  493. 'first.last@[IPv6:1111:2222:3333:4444:5555:12.34.56.78]',
  494. 'first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777:12.34.56.78]',
  495. 'first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777]',
  496. 'first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888:9999]',
  497. 'first.last@[IPv6:1111:2222::3333::4444:5555:6666]',
  498. 'first.last@[IPv6:1111:2222:333x::4444:5555]',
  499. 'first.last@[IPv6:1111:2222:33333::4444:5555]',
  500. 'first.last@-xample.com',
  501. 'first.last@exampl-.com',
  502. 'first.last@x234567890123456789012345678901234567890123456789012345678901234.iana.org',
  503. 'abc\@def@iana.org',
  504. 'abc\@iana.org',
  505. 'Doug\ \"Ace\"\ Lovell@iana.org',
  506. 'abc@def@iana.org',
  507. 'abc\@def@iana.org',
  508. 'abc\@iana.org',
  509. '@iana.org',
  510. 'doug@',
  511. '"qu@iana.org',
  512. 'ote"@iana.org',
  513. '.dot@iana.org',
  514. 'dot.@iana.org',
  515. 'two..dot@iana.org',
  516. '"Doug "Ace" L."@iana.org',
  517. 'Doug\ \"Ace\"\ L\.@iana.org',
  518. 'hello world@iana.org',
  519. //'helloworld@iana .org',
  520. 'gatsby@f.sc.ot.t.f.i.tzg.era.l.d.',
  521. 'test.iana.org',
  522. 'test.@iana.org',
  523. 'test..test@iana.org',
  524. '.test@iana.org',
  525. 'test@test@iana.org',
  526. 'test@@iana.org',
  527. '-- test --@iana.org',
  528. '[test]@iana.org',
  529. '"test"test"@iana.org',
  530. '()[]\;:,><@iana.org',
  531. 'test@.',
  532. 'test@example.',
  533. 'test@.org',
  534. 'test@12345678901234567890123456789012345678901234567890123456789012345678901234567890' .
  535. '12345678901234567890 [...]',
  536. 'test@[123.123.123.123',
  537. 'test@123.123.123.123]',
  538. 'NotAnEmail',
  539. '@NotAnEmail',
  540. '"test"blah"@iana.org',
  541. '.wooly@iana.org',
  542. 'wo..oly@iana.org',
  543. 'pootietang.@iana.org',
  544. '.@iana.org',
  545. 'Ima Fool@iana.org',
  546. 'phil.h\@\@ck@haacked.com',
  547. 'foo@[\1.2.3.4]',
  548. //'first."".last@iana.org',
  549. 'first\last@iana.org',
  550. 'Abc\@def@iana.org',
  551. 'Fred\ Bloggs@iana.org',
  552. 'Joe.\Blow@iana.org',
  553. 'first.last@[IPv6:1111:2222:3333:4444:5555:6666:12.34.567.89]',
  554. '{^c\@**Dog^}@cartoon.com',
  555. //'"foo"(yay)@(hoopla)[1.2.3.4]',
  556. 'cal(foo(bar)@iamcal.com',
  557. 'cal(foo)bar)@iamcal.com',
  558. 'cal(foo\)@iamcal.com',
  559. 'first(12345678901234567890123456789012345678901234567890)last@(1234567890123456789' .
  560. '01234567890123456789012 [...]',
  561. 'first(middle)last@iana.org',
  562. 'first(abc("def".ghi).mno)middle(abc("def".ghi).mno).last@(abc("def".ghi).mno)example' .
  563. '(abc("def".ghi).mno). [...]',
  564. 'a(a(b(c)d(e(f))g)(h(i)j)@iana.org',
  565. '.@',
  566. '@bar.com',
  567. '@@bar.com',
  568. 'aaa.com',
  569. 'aaa@.com',
  570. 'aaa@.123',
  571. 'aaa@[123.123.123.123]a',
  572. 'aaa@[123.123.123.333]',
  573. 'a@bar.com.',
  574. 'a@-b.com',
  575. 'a@b-.com',
  576. '-@..com',
  577. '-@a..com',
  578. 'invalid@about.museum-',
  579. 'test@...........com',
  580. '"Unicode NULL' . chr(0) . '"@char.com',
  581. 'Unicode NULL' . chr(0) . '@char.com',
  582. 'first.last@[IPv6::]',
  583. 'first.last@[IPv6::::]',
  584. 'first.last@[IPv6::b4]',
  585. 'first.last@[IPv6::::b4]',
  586. 'first.last@[IPv6::b3:b4]',
  587. 'first.last@[IPv6::::b3:b4]',
  588. 'first.last@[IPv6:a1:::b4]',
  589. 'first.last@[IPv6:a1:]',
  590. 'first.last@[IPv6:a1:::]',
  591. 'first.last@[IPv6:a1:a2:]',
  592. 'first.last@[IPv6:a1:a2:::]',
  593. 'first.last@[IPv6::11.22.33.44]',
  594. 'first.last@[IPv6::::11.22.33.44]',
  595. 'first.last@[IPv6:a1:11.22.33.44]',
  596. 'first.last@[IPv6:a1:::11.22.33.44]',
  597. 'first.last@[IPv6:a1:a2:::11.22.33.44]',
  598. 'first.last@[IPv6:0123:4567:89ab:cdef::11.22.33.xx]',
  599. 'first.last@[IPv6:0123:4567:89ab:CDEFF::11.22.33.44]',
  600. 'first.last@[IPv6:a1::a4:b1::b4:11.22.33.44]',
  601. 'first.last@[IPv6:a1::11.22.33]',
  602. 'first.last@[IPv6:a1::11.22.33.44.55]',
  603. 'first.last@[IPv6:a1::b211.22.33.44]',
  604. 'first.last@[IPv6:a1::b2::11.22.33.44]',
  605. 'first.last@[IPv6:a1::b3:]',
  606. 'first.last@[IPv6::a2::b4]',
  607. 'first.last@[IPv6:a1:a2:a3:a4:b1:b2:b3:]',
  608. 'first.last@[IPv6::a2:a3:a4:b1:b2:b3:b4]',
  609. 'first.last@[IPv6:a1:a2:a3:a4::b1:b2:b3:b4]',
  610. "(\r\n RCPT TO:websec02@d.mbsd.jp\r\n DATA \\\nSubject: spam10\\\n\r\n Hello,\r\n this is a spam mail.\\\n.\r\n QUIT\r\n ) a@gmail.com" //This is valid RCC5322, but we don't want to allow it
  611. );
  612. // IDNs in Unicode and ASCII forms.
  613. $unicodeaddresses = array(
  614. 'first.last@bücher.ch',
  615. 'first.last@кто.рф',
  616. 'first.last@phplíst.com',
  617. );
  618. $asciiaddresses = array(
  619. 'first.last@xn--bcher-kva.ch',
  620. 'first.last@xn--j1ail.xn--p1ai',
  621. 'first.last@xn--phplst-6va.com',
  622. );
  623. $goodfails = array();
  624. foreach (array_merge($validaddresses, $asciiaddresses) as $address) {
  625. if (!PHPMailer::validateAddress($address)) {
  626. $goodfails[] = $address;
  627. }
  628. }
  629. $badpasses = array();
  630. foreach (array_merge($invalidaddresses, $unicodeaddresses) as $address) {
  631. if (PHPMailer::validateAddress($address)) {
  632. $badpasses[] = $address;
  633. }
  634. }
  635. $err = '';
  636. if (count($goodfails) > 0) {
  637. $err .= "Good addresses that failed validation:\n";
  638. $err .= implode("\n", $goodfails);
  639. }
  640. if (count($badpasses) > 0) {
  641. if (!empty($err)) {
  642. $err .= "\n\n";
  643. }
  644. $err .= "Bad addresses that passed validation:\n";
  645. $err .= implode("\n", $badpasses);
  646. }
  647. $this->assertEmpty($err, $err);
  648. //For coverage
  649. $this->assertTrue(PHPMailer::validateAddress('test@example.com', 'auto'));
  650. $this->assertFalse(PHPMailer::validateAddress('test@example.com.', 'auto'));
  651. $this->assertTrue(PHPMailer::validateAddress('test@example.com', 'pcre'));
  652. $this->assertFalse(PHPMailer::validateAddress('test@example.com.', 'pcre'));
  653. $this->assertTrue(PHPMailer::validateAddress('test@example.com', 'pcre8'));
  654. $this->assertFalse(PHPMailer::validateAddress('test@example.com.', 'pcre8'));
  655. $this->assertTrue(PHPMailer::validateAddress('test@example.com', 'php'));
  656. $this->assertFalse(PHPMailer::validateAddress('test@example.com.', 'php'));
  657. $this->assertTrue(PHPMailer::validateAddress('test@example.com', 'noregex'));
  658. $this->assertFalse(PHPMailer::validateAddress('bad', 'noregex'));
  659. }
  660.  
  661. /**
  662. * Word-wrap an ASCII message.
  663. */
  664. public function testWordWrap()
  665. {
  666. $this->Mail->WordWrap = 40;
  667. $my_body = str_repeat(
  668. 'Here is the main body of this message. It should ' .
  669. 'be quite a few lines. It should be wrapped at ' .
  670. '40 characters. Make sure that it is. ',
  671. 10
  672. );
  673. $nBodyLen = strlen($my_body);
  674. $my_body .= "\n\nThis is the above body length: " . $nBodyLen;
  675.  
  676. $this->Mail->Body = $my_body;
  677. $this->Mail->Subject .= ': Wordwrap';
  678.  
  679. $this->buildBody();
  680. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  681. }
  682.  
  683. /**
  684. * Word-wrap a multibyte message.
  685. */
  686. public function testWordWrapMultibyte()
  687. {
  688. $this->Mail->WordWrap = 40;
  689. $my_body = str_repeat(
  690. '飛兒樂 團光茫 飛兒樂 團光茫 飛兒樂 團光茫 飛兒樂 團光茫 ' .
  691. '飛飛兒樂 團光茫兒樂 團光茫飛兒樂 團光飛兒樂 團光茫飛兒樂 團光茫兒樂 團光茫 ' .
  692. '飛兒樂 團光茫飛兒樂 團飛兒樂 團光茫光茫飛兒樂 團光茫. ',
  693. 10
  694. );
  695. $nBodyLen = strlen($my_body);
  696. $my_body .= "\n\nThis is the above body length: " . $nBodyLen;
  697.  
  698. $this->Mail->Body = $my_body;
  699. $this->Mail->Subject .= ': Wordwrap multibyte';
  700.  
  701. $this->buildBody();
  702. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  703. }
  704.  
  705. /**
  706. * Test low priority.
  707. */
  708. public function testLowPriority()
  709. {
  710. $this->Mail->Priority = 5;
  711. $this->Mail->Body = 'Here is the main body. There should be ' .
  712. 'a reply to address in this message.';
  713. $this->Mail->Subject .= ': Low Priority';
  714. $this->Mail->addReplyTo('nobody@nobody.com', 'Nobody (Unit Test)');
  715.  
  716. $this->buildBody();
  717. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  718. }
  719.  
  720. /**
  721. * Simple plain file attachment test.
  722. */
  723. public function testMultiplePlainFileAttachment()
  724. {
  725. $this->Mail->Body = 'Here is the text body';
  726. $this->Mail->Subject .= ': Plain + Multiple FileAttachments';
  727.  
  728. if (!$this->Mail->addAttachment('../examples/images/phpmailer.png')) {
  729. $this->assertTrue(false, $this->Mail->ErrorInfo);
  730. return;
  731. }
  732.  
  733. if (!$this->Mail->addAttachment(__FILE__, 'test.txt')) {
  734. $this->assertTrue(false, $this->Mail->ErrorInfo);
  735. return;
  736. }
  737.  
  738. $this->buildBody();
  739. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  740. }
  741.  
  742. /**
  743. * Simple plain string attachment test.
  744. */
  745. public function testPlainStringAttachment()
  746. {
  747. $this->Mail->Body = 'Here is the text body';
  748. $this->Mail->Subject .= ': Plain + StringAttachment';
  749.  
  750. $sAttachment = 'These characters are the content of the ' .
  751. "string attachment.\nThis might be taken from a " .
  752. 'database or some other such thing. ';
  753.  
  754. $this->Mail->addStringAttachment($sAttachment, 'string_attach.txt');
  755.  
  756. $this->buildBody();
  757. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  758. }
  759.  
  760. /**
  761. * Plain quoted-printable message.
  762. */
  763. public function testQuotedPrintable()
  764. {
  765. $this->Mail->Body = 'Here is the main body';
  766. $this->Mail->Subject .= ': Plain + Quoted-printable';
  767. $this->Mail->Encoding = 'quoted-printable';
  768.  
  769. $this->buildBody();
  770. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  771.  
  772. //Check that a quoted printable encode and decode results in the same as went in
  773. $t = file_get_contents(__FILE__); //Use this file as test content
  774. //Force line breaks to UNIX-style
  775. $t = str_replace(array("\r\n", "\r"), "\n", $t);
  776. $this->assertEquals(
  777. $t,
  778. quoted_printable_decode($this->Mail->encodeQP($t)),
  779. 'Quoted-Printable encoding round-trip failed'
  780. );
  781. $this->assertEquals(
  782. $this->Mail->encodeQP($t),
  783. $this->Mail->encodeQPphp($t),
  784. 'Quoted-Printable BC wrapper failed'
  785. );
  786. //Force line breaks to Windows-style
  787. $t = str_replace("\n", "\r\n", $t);
  788. $this->assertEquals(
  789. $t,
  790. quoted_printable_decode($this->Mail->encodeQP($t)),
  791. 'Quoted-Printable encoding round-trip failed (Windows line breaks)'
  792. );
  793. }
  794.  
  795. /**
  796. * Send an HTML message.
  797. */
  798. public function testHtml()
  799. {
  800. $this->Mail->isHTML(true);
  801. $this->Mail->Subject .= ": HTML only";
  802.  
  803. $this->Mail->Body = <<<EOT
  804. <html>
  805. <head>
  806. <title>HTML email test</title>
  807. </head>
  808. <body>
  809. <h1>PHPMailer does HTML!</h1>
  810. <p>This is a <strong>test message</strong> written in HTML.<br>
  811. Go to <a href="https://github.com/PHPMailer/PHPMailer/">https://github.com/PHPMailer/PHPMailer/</a>
  812. for new versions of PHPMailer.</p>
  813. <p>Thank you!</p>
  814. </body>
  815. </html>
  816. EOT;
  817. $this->buildBody();
  818. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  819. $msg = $this->Mail->getSentMIMEMessage();
  820. $this->assertNotContains("\r\n\r\nMIME-Version:", $msg, 'Incorrect MIME headers');
  821. }
  822.  
  823. /**
  824. * Send a message containing ISO-8859-1 text.
  825. */
  826. public function testHtmlIso8859()
  827. {
  828. $this->Mail->isHTML(true);
  829. $this->Mail->Subject .= ": ISO-8859-1 HTML";
  830. $this->Mail->CharSet = 'iso-8859-1';
  831.  
  832. //This file is in ISO-8859-1 charset
  833. //Needs to be external because this file is in UTF-8
  834. $content = file_get_contents('../examples/contents.html');
  835. // This is the string 'éèîüçÅñæß' in ISO-8859-1, base-64 encoded
  836. $check = base64_decode('6eju/OfF8ebf');
  837. //Make sure it really is in ISO-8859-1!
  838. $this->Mail->msgHTML(
  839. mb_convert_encoding(
  840. $content,
  841. "ISO-8859-1",
  842. mb_detect_encoding($content, "UTF-8, ISO-8859-1, ISO-8859-15", true)
  843. ),
  844. '../examples'
  845. );
  846. $this->buildBody();
  847. $this->assertTrue(
  848. strpos($this->Mail->Body, $check) !== false,
  849. 'ISO message body does not contain expected text'
  850. );
  851. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  852. }
  853.  
  854. /**
  855. * Send a message containing multilingual UTF-8 text.
  856. */
  857. public function testHtmlUtf8()
  858. {
  859. $this->Mail->isHTML(true);
  860. $this->Mail->Subject .= ": UTF-8 HTML";
  861. $this->Mail->CharSet = 'UTF-8';
  862.  
  863. $this->Mail->Body = <<<EOT
  864. <html>
  865. <head>
  866. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  867. <title>HTML email test</title>
  868. </head>
  869. <body>
  870. <p>Chinese text: 郵件內容為空</p>
  871. <p>Russian text: Пустое тело сообщения</p>
  872. <p>Armenian text: Հաղորդագրությունը դատարկ է</p>
  873. <p>Czech text: Prázdné tělo zprávy</p>
  874. </body>
  875. </html>
  876. EOT;
  877. $this->buildBody();
  878. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  879. $msg = $this->Mail->getSentMIMEMessage();
  880. $this->assertNotContains("\r\n\r\nMIME-Version:", $msg, 'Incorrect MIME headers');
  881. }
  882.  
  883. /**
  884. * Send a message containing multilingual UTF-8 text with an embedded image.
  885. */
  886. public function testUtf8WithEmbeddedImage()
  887. {
  888. $this->Mail->isHTML(true);
  889. $this->Mail->Subject .= ": UTF-8 with embedded image";
  890. $this->Mail->CharSet = 'UTF-8';
  891.  
  892. $this->Mail->Body = <<<EOT
  893. <html>
  894. <head>
  895. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  896. <title>HTML email test</title>
  897. </head>
  898. <body>
  899. <p>Chinese text: 郵件內容為空</p>
  900. <p>Russian text: Пустое тело сообщения</p>
  901. <p>Armenian text: Հաղորդագրությունը դատարկ է</p>
  902. <p>Czech text: Prázdné tělo zprávy</p>
  903. Embedded Image: <img alt="phpmailer" src="cid:my-attach">
  904. </body>
  905. </html>
  906. EOT;
  907. $this->Mail->addEmbeddedImage(
  908. '../examples/images/phpmailer.png',
  909. 'my-attach',
  910. 'phpmailer.png',
  911. 'base64',
  912. 'image/png'
  913. );
  914. $this->buildBody();
  915. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  916. }
  917.  
  918. /**
  919. * Send a message containing multilingual UTF-8 text.
  920. */
  921. public function testPlainUtf8()
  922. {
  923. $this->Mail->isHTML(false);
  924. $this->Mail->Subject .= ": UTF-8 plain text";
  925. $this->Mail->CharSet = 'UTF-8';
  926.  
  927. $this->Mail->Body = <<<EOT
  928. Chinese text: 郵件內容為空
  929. Russian text: Пустое тело сообщения
  930. Armenian text: Հաղորդագրությունը դատարկ է
  931. Czech text: Prázdné tělo zprávy
  932. EOT;
  933. $this->buildBody();
  934. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  935. $msg = $this->Mail->getSentMIMEMessage();
  936. $this->assertNotContains("\r\n\r\nMIME-Version:", $msg, 'Incorrect MIME headers');
  937. }
  938.  
  939. /**
  940. * Test simple message builder and html2text converters
  941. */
  942. public function testMsgHTML()
  943. {
  944. $message = file_get_contents('../examples/contentsutf8.html');
  945. $this->Mail->CharSet = 'utf-8';
  946. $this->Mail->Body = '';
  947. $this->Mail->AltBody = '';
  948. //Uses internal HTML to text conversion
  949. $this->Mail->msgHTML($message, '../examples');
  950. $this->Mail->Subject .= ': msgHTML';
  951.  
  952. $this->assertNotEmpty($this->Mail->Body, 'Body not set by msgHTML');
  953. $this->assertNotEmpty($this->Mail->AltBody, 'AltBody not set by msgHTML');
  954. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  955.  
  956. //Again, using a custom HTML to text converter
  957. $this->Mail->AltBody = '';
  958. $this->Mail->msgHTML($message, '../examples', function ($html) {
  959. return strtoupper(strip_tags($html));
  960. });
  961. $this->Mail->Subject .= ' + custom html2text';
  962. $this->assertNotEmpty($this->Mail->AltBody, 'Custom AltBody not set by msgHTML');
  963.  
  964. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  965. }
  966.  
  967. /**
  968. * Simple HTML and attachment test
  969. */
  970. public function testHTMLAttachment()
  971. {
  972. $this->Mail->Body = 'This is the <strong>HTML</strong> part of the email.';
  973. $this->Mail->Subject .= ': HTML + Attachment';
  974. $this->Mail->isHTML(true);
  975.  
  976. if (!$this->Mail->addAttachment('../examples/images/phpmailer_mini.png', 'phpmailer_mini.png')) {
  977. $this->assertTrue(false, $this->Mail->ErrorInfo);
  978. return;
  979. }
  980.  
  981. //Make sure that trying to attach a nonexistent file fails
  982. $this->assertFalse($this->Mail->addAttachment(__FILE__ . md5(microtime()), 'nonexistent_file.txt'));
  983.  
  984. $this->buildBody();
  985. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  986. }
  987.  
  988. /**
  989. * Test embedded image without a name
  990. */
  991. public function testHTMLStringEmbedNoName()
  992. {
  993. $this->Mail->Body = 'This is the <strong>HTML</strong> part of the email.';
  994. $this->Mail->Subject .= ': HTML + unnamed embedded image';
  995. $this->Mail->isHTML(true);
  996.  
  997. if (!$this->Mail->addStringEmbeddedImage(
  998. file_get_contents('../examples/images/phpmailer_mini.png'),
  999. md5('phpmailer_mini.png').'@phpmailer.0',
  1000. '', //intentionally empty name
  1001. 'base64',
  1002. 'image/png',
  1003. 'inline')
  1004. ) {
  1005. $this->assertTrue(false, $this->Mail->ErrorInfo);
  1006. return;
  1007. }
  1008.  
  1009. $this->buildBody();
  1010. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1011. }
  1012.  
  1013. /**
  1014. * Simple HTML and multiple attachment test
  1015. */
  1016. public function testHTMLMultiAttachment()
  1017. {
  1018. $this->Mail->Body = 'This is the <strong>HTML</strong> part of the email.';
  1019. $this->Mail->Subject .= ': HTML + multiple Attachment';
  1020. $this->Mail->isHTML(true);
  1021.  
  1022. if (!$this->Mail->addAttachment('../examples/images/phpmailer_mini.png', 'phpmailer_mini.png')) {
  1023. $this->assertTrue(false, $this->Mail->ErrorInfo);
  1024. return;
  1025. }
  1026.  
  1027. if (!$this->Mail->addAttachment('../examples/images/phpmailer.png', 'phpmailer.png')) {
  1028. $this->assertTrue(false, $this->Mail->ErrorInfo);
  1029. return;
  1030. }
  1031.  
  1032. $this->buildBody();
  1033. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1034. }
  1035.  
  1036. /**
  1037. * An embedded attachment test.
  1038. */
  1039. public function testEmbeddedImage()
  1040. {
  1041. $this->Mail->Body = 'Embedded Image: <img alt="phpmailer" src="cid:my-attach">' .
  1042. 'Here is an image!';
  1043. $this->Mail->Subject .= ': Embedded Image';
  1044. $this->Mail->isHTML(true);
  1045.  
  1046. if (!$this->Mail->addEmbeddedImage(
  1047. '../examples/images/phpmailer.png',
  1048. 'my-attach',
  1049. 'phpmailer.png',
  1050. 'base64',
  1051. 'image/png'
  1052. )
  1053. ) {
  1054. $this->assertTrue(false, $this->Mail->ErrorInfo);
  1055. return;
  1056. }
  1057.  
  1058. $this->buildBody();
  1059. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1060. //For code coverage
  1061. $this->Mail->addEmbeddedImage('thisfiledoesntexist', 'xyz'); //Non-existent file
  1062. $this->Mail->addEmbeddedImage(__FILE__, '123'); //Missing name
  1063. }
  1064.  
  1065. /**
  1066. * An embedded attachment test.
  1067. */
  1068. public function testMultiEmbeddedImage()
  1069. {
  1070. $this->Mail->Body = 'Embedded Image: <img alt="phpmailer" src="cid:my-attach">' .
  1071. 'Here is an image!</a>';
  1072. $this->Mail->Subject .= ': Embedded Image + Attachment';
  1073. $this->Mail->isHTML(true);
  1074.  
  1075. if (!$this->Mail->addEmbeddedImage(
  1076. '../examples/images/phpmailer.png',
  1077. 'my-attach',
  1078. 'phpmailer.png',
  1079. 'base64',
  1080. 'image/png'
  1081. )
  1082. ) {
  1083. $this->assertTrue(false, $this->Mail->ErrorInfo);
  1084. return;
  1085. }
  1086.  
  1087. if (!$this->Mail->addAttachment(__FILE__, 'test.txt')) {
  1088. $this->assertTrue(false, $this->Mail->ErrorInfo);
  1089. return;
  1090. }
  1091.  
  1092. $this->buildBody();
  1093. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1094. }
  1095.  
  1096. /**
  1097. * Simple multipart/alternative test.
  1098. */
  1099. public function testAltBody()
  1100. {
  1101. $this->Mail->Body = 'This is the <strong>HTML</strong> part of the email.';
  1102. $this->Mail->AltBody = 'Here is the text body of this message. ' .
  1103. 'It should be quite a few lines. It should be wrapped at the ' .
  1104. '40 characters. Make sure that it is.';
  1105. $this->Mail->WordWrap = 40;
  1106. $this->addNote('This is a mulipart alternative email');
  1107. $this->Mail->Subject .= ': AltBody + Word Wrap';
  1108.  
  1109. $this->buildBody();
  1110. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1111. }
  1112.  
  1113. /**
  1114. * Simple HTML and attachment test
  1115. */
  1116. public function testAltBodyAttachment()
  1117. {
  1118. $this->Mail->Body = 'This is the <strong>HTML</strong> part of the email.';
  1119. $this->Mail->AltBody = 'This is the text part of the email.';
  1120. $this->Mail->Subject .= ': AltBody + Attachment';
  1121. $this->Mail->isHTML(true);
  1122.  
  1123. if (!$this->Mail->addAttachment(__FILE__, 'test_attach.txt')) {
  1124. $this->assertTrue(false, $this->Mail->ErrorInfo);
  1125. return;
  1126. }
  1127.  
  1128. $this->buildBody();
  1129. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1130. if (is_writable('.')) {
  1131. file_put_contents('message.txt', $this->Mail->createHeader() . $this->Mail->createBody());
  1132. } else {
  1133. $this->assertTrue(false, 'Could not write local file - check permissions');
  1134. }
  1135. }
  1136.  
  1137. /**
  1138. * iCal event test.
  1139. */
  1140. public function testIcal()
  1141. {
  1142. //Standalone ICS tests
  1143. require_once '../extras/EasyPeasyICS.php';
  1144. $ICS = new EasyPeasyICS("PHPMailer test calendar");
  1145. $this->assertNotEmpty(
  1146. $ICS->addEvent(
  1147. strtotime('tomorrow 10:00 Europe/Paris'),
  1148. strtotime('tomorrow 11:00 Europe/Paris'),
  1149. 'PHPMailer iCal test',
  1150. 'A test of PHPMailer iCal support',
  1151. 'https://github.com/PHPMailer/PHPMailer'
  1152. ),
  1153. 'Generated event string is empty'
  1154. );
  1155. $ICS->addEvent(
  1156. strtotime('tomorrow 10:00 Europe/Paris'),
  1157. strtotime('tomorrow 11:00 Europe/Paris'),
  1158. 'PHPMailer iCal test',
  1159. 'A test of PHPMailer iCal support',
  1160. 'https://github.com/PHPMailer/PHPMailer'
  1161. );
  1162. $events = $ICS->getEvents();
  1163. $this->assertEquals(2, count($events), 'Event count mismatch');
  1164. $ICS->clearEvents();
  1165. $events = $ICS->getEvents();
  1166. $this->assertEquals(0, count($events), 'Event clearing failed');
  1167. $ICS->setName('test');
  1168. $this->assertEquals('test', $ICS->getName(), 'Setting ICS name failed');
  1169. $this->assertNotEmpty($ICS->render(false), 'Empty calendar');
  1170. //Need to test generated output but PHPUnit isn't playing nice
  1171. //$rendered = $ICS->render();
  1172.  
  1173. //Test sending an ICS
  1174. $this->Mail->Body = 'This is the <strong>HTML</strong> part of the email.';
  1175. $this->Mail->AltBody = 'This is the text part of the email.';
  1176. $this->Mail->Subject .= ': iCal';
  1177. $this->Mail->isHTML(true);
  1178. $this->buildBody();
  1179. $this->Mail->Ical = $ICS->render(false);
  1180. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1181. }
  1182.  
  1183. /**
  1184. * Test sending multiple messages with separate connections.
  1185. */
  1186. public function testMultipleSend()
  1187. {
  1188. $this->Mail->Body = 'Sending two messages without keepalive';
  1189. $this->buildBody();
  1190. $subject = $this->Mail->Subject;
  1191.  
  1192. $this->Mail->Subject = $subject . ': SMTP 1';
  1193. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1194.  
  1195. $this->Mail->Subject = $subject . ': SMTP 2';
  1196. $this->Mail->Sender = 'blah@example.com';
  1197. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1198. }
  1199.  
  1200. /**
  1201. * Test sending using SendMail.
  1202. */
  1203. public function testSendmailSend()
  1204. {
  1205. $this->Mail->Body = 'Sending via sendmail';
  1206. $this->buildBody();
  1207. $subject = $this->Mail->Subject;
  1208.  
  1209. $this->Mail->Subject = $subject . ': sendmail';
  1210. $this->Mail->isSendmail();
  1211. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1212. }
  1213.  
  1214. /**
  1215. * Test sending using Qmail.
  1216. */
  1217. public function testQmailSend()
  1218. {
  1219. //Only run if we have qmail installed
  1220. if (file_exists('/var/qmail/bin/qmail-inject')) {
  1221. $this->Mail->Body = 'Sending via qmail';
  1222. $this->BuildBody();
  1223. $subject = $this->Mail->Subject;
  1224.  
  1225. $this->Mail->Subject = $subject . ': qmail';
  1226. $this->Mail->IsQmail();
  1227. $this->assertTrue($this->Mail->Send(), $this->Mail->ErrorInfo);
  1228. } else {
  1229. $this->markTestSkipped('Qmail is not installed');
  1230. }
  1231. }
  1232.  
  1233. /**
  1234. * Test sending using PHP mail() function.
  1235. */
  1236. public function testMailSend()
  1237. {
  1238. $sendmail = ini_get('sendmail_path');
  1239. //No path in sendmail_path
  1240. if (strpos($sendmail, '/') === false) {
  1241. ini_set('sendmail_path', '/usr/sbin/sendmail -t -i ');
  1242. }
  1243. $this->Mail->Body = 'Sending via mail()';
  1244. $this->buildBody();
  1245.  
  1246. $this->Mail->Subject = $this->Mail->Subject . ': mail()';
  1247. $this->Mail->isMail();
  1248. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1249. $msg = $this->Mail->getSentMIMEMessage();
  1250. $this->assertNotContains("\r\n\r\nMIME-Version:", $msg, 'Incorrect MIME headers');
  1251. }
  1252.  
  1253. /**
  1254. * Test sending an empty body.
  1255. */
  1256. public function testEmptyBody()
  1257. {
  1258. $this->buildBody();
  1259. $this->Mail->Body = '';
  1260. $this->Mail->Subject = $this->Mail->Subject . ': Empty Body';
  1261. $this->Mail->isMail();
  1262. $this->Mail->AllowEmpty = true;
  1263. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1264. $this->Mail->AllowEmpty = false;
  1265. $this->assertFalse($this->Mail->send(), $this->Mail->ErrorInfo);
  1266. }
  1267.  
  1268. /**
  1269. * Test constructing a message that contains lines that are too long for RFC compliance.
  1270. */
  1271. public function testLongBody()
  1272. {
  1273. $oklen = str_repeat(str_repeat('0', PHPMailer::MAX_LINE_LENGTH) . PHPMailer::CRLF, 10);
  1274. $badlen = str_repeat(str_repeat('1', PHPMailer::MAX_LINE_LENGTH + 1) . PHPMailer::CRLF, 2);
  1275.  
  1276. $this->Mail->Body = "This message contains lines that are too long.".
  1277. PHPMailer::CRLF . PHPMailer::CRLF . $oklen . $badlen . $oklen;
  1278. $this->assertTrue(
  1279. PHPMailer::hasLineLongerThanMax($this->Mail->Body),
  1280. 'Test content does not contain long lines!'
  1281. );
  1282. $this->buildBody();
  1283. $this->Mail->Encoding = '8bit';
  1284. $this->Mail->preSend();
  1285. $message = $this->Mail->getSentMIMEMessage();
  1286. $this->assertFalse(PHPMailer::hasLineLongerThanMax($message), 'Long line not corrected.');
  1287. $this->assertContains(
  1288. 'Content-Transfer-Encoding: quoted-printable',
  1289. $message,
  1290. 'Long line did not cause transfer encoding switch.'
  1291. );
  1292. }
  1293.  
  1294. /**
  1295. * Test constructing a message that does NOT contain lines that are too long for RFC compliance.
  1296. */
  1297. public function testShortBody()
  1298. {
  1299. $oklen = str_repeat(str_repeat('0', PHPMailer::MAX_LINE_LENGTH) . PHPMailer::CRLF, 10);
  1300.  
  1301. $this->Mail->Body = "This message does not contain lines that are too long.".
  1302. PHPMailer::CRLF . PHPMailer::CRLF . $oklen;
  1303. $this->assertFalse(
  1304. PHPMailer::hasLineLongerThanMax($this->Mail->Body),
  1305. 'Test content contains long lines!'
  1306. );
  1307. $this->buildBody();
  1308. $this->Mail->Encoding = '8bit';
  1309. $this->Mail->preSend();
  1310. $message = $this->Mail->getSentMIMEMessage();
  1311. $this->assertFalse(PHPMailer::hasLineLongerThanMax($message), 'Long line not corrected.');
  1312. $this->assertNotContains(
  1313. 'Content-Transfer-Encoding: quoted-printable',
  1314. $message,
  1315. 'Short line caused transfer encoding switch.'
  1316. );
  1317. }
  1318.  
  1319. /**
  1320. * Test keepalive (sending multiple messages in a single connection).
  1321. */
  1322. public function testSmtpKeepAlive()
  1323. {
  1324. $this->Mail->Body = 'SMTP keep-alive test.';
  1325. $this->buildBody();
  1326. $subject = $this->Mail->Subject;
  1327.  
  1328. $this->Mail->SMTPKeepAlive = true;
  1329. $this->Mail->Subject = $subject . ': SMTP keep-alive 1';
  1330. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1331.  
  1332. $this->Mail->Subject = $subject . ': SMTP keep-alive 2';
  1333. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1334. $this->Mail->smtpClose();
  1335. }
  1336.  
  1337. /**
  1338. * Tests this denial of service attack:
  1339. * @link http://www.cybsec.com/vuln/PHPMailer-DOS.pdf
  1340. */
  1341. public function testDenialOfServiceAttack()
  1342. {
  1343. $this->Mail->Body = 'This should no longer cause a denial of service.';
  1344. $this->buildBody();
  1345.  
  1346. $this->Mail->Subject = substr(str_repeat('0123456789', 100), 0, 998);
  1347. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1348. }
  1349.  
  1350. /**
  1351. * Tests this denial of service attack:
  1352. * @link https://sourceforge.net/p/phpmailer/bugs/383/
  1353. * According to the ticket, this should get stuck in a loop, though I can't make it happen.
  1354. * @TODO No assertions in here - how can you assert for this?
  1355. */
  1356. public function testDenialOfServiceAttack2()
  1357. {
  1358. //Encoding name longer than 68 chars
  1359. $this->Mail->Encoding = '1234567890123456789012345678901234567890123456789012345678901234567890';
  1360. //Call wrapText with a zero length value
  1361. $this->Mail->wrapText(str_repeat('This should no longer cause a denial of service. ', 30), 0);
  1362. }
  1363.  
  1364. /**
  1365. * Test error handling.
  1366. */
  1367. public function testError()
  1368. {
  1369. $this->Mail->Subject .= ': Error handling test - this should be sent ok';
  1370. $this->buildBody();
  1371. $this->Mail->clearAllRecipients(); // no addresses should cause an error
  1372. $this->assertTrue($this->Mail->isError() == false, 'Error found');
  1373. $this->assertTrue($this->Mail->send() == false, 'send succeeded');
  1374. $this->assertTrue($this->Mail->isError(), 'No error found');
  1375. $this->assertEquals('You must provide at least one recipient email address.', $this->Mail->ErrorInfo);
  1376. $this->Mail->addAddress($_REQUEST['mail_to']);
  1377. $this->assertTrue($this->Mail->send(), 'send failed');
  1378. }
  1379.  
  1380. /**
  1381. * Test addressing.
  1382. */
  1383. public function testAddressing()
  1384. {
  1385. $this->assertFalse($this->Mail->addAddress(''), 'Empty address accepted');
  1386. $this->assertFalse($this->Mail->addAddress('', 'Nobody'), 'Empty address with name accepted');
  1387. $this->assertFalse($this->Mail->addAddress('a@example..com'), 'Invalid address accepted');
  1388. $this->assertTrue($this->Mail->addAddress('a@example.com'), 'Addressing failed');
  1389. $this->assertFalse($this->Mail->addAddress('a@example.com'), 'Duplicate addressing failed');
  1390. $this->assertTrue($this->Mail->addCC('b@example.com'), 'CC addressing failed');
  1391. $this->assertFalse($this->Mail->addCC('b@example.com'), 'CC duplicate addressing failed');
  1392. $this->assertFalse($this->Mail->addCC('a@example.com'), 'CC duplicate addressing failed (2)');
  1393. $this->assertTrue($this->Mail->addBCC('c@example.com'), 'BCC addressing failed');
  1394. $this->assertFalse($this->Mail->addBCC('c@example.com'), 'BCC duplicate addressing failed');
  1395. $this->assertFalse($this->Mail->addBCC('a@example.com'), 'BCC duplicate addressing failed (2)');
  1396. $this->assertTrue($this->Mail->addReplyTo('a@example.com'), 'Replyto Addressing failed');
  1397. $this->assertFalse($this->Mail->addReplyTo('a@example..com'), 'Invalid Replyto address accepted');
  1398. $this->assertTrue($this->Mail->setFrom('a@example.com', 'some name'), 'setFrom failed');
  1399. $this->assertFalse($this->Mail->setFrom('a@example.com.', 'some name'), 'setFrom accepted invalid address');
  1400. $this->Mail->Sender = '';
  1401. $this->Mail->setFrom('a@example.com', 'some name', true);
  1402. $this->assertEquals($this->Mail->Sender, 'a@example.com', 'setFrom failed to set sender');
  1403. $this->Mail->Sender = '';
  1404. $this->Mail->setFrom('a@example.com', 'some name', false);
  1405. $this->assertEquals($this->Mail->Sender, '', 'setFrom should not have set sender');
  1406. $this->Mail->clearCCs();
  1407. $this->Mail->clearBCCs();
  1408. $this->Mail->clearReplyTos();
  1409. }
  1410.  
  1411. /**
  1412. * Test RFC822 address splitting.
  1413. */
  1414. public function testAddressSplitting()
  1415. {
  1416. //Test built-in address parser
  1417. $this->assertCount(
  1418. 2,
  1419. $this->Mail->parseAddresses(
  1420. 'Joe User <joe@example.com>, Jill User <jill@example.net>'
  1421. ),
  1422. 'Failed to recognise address list (IMAP parser)'
  1423. );
  1424. //Test simple address parser
  1425. $this->assertCount(
  1426. 2,
  1427. $this->Mail->parseAddresses(
  1428. 'Joe User <joe@example.com>, Jill User <jill@example.net>',
  1429. false
  1430. ),
  1431. 'Failed to recognise address list'
  1432. );
  1433. //Test single address
  1434. $this->assertNotEmpty(
  1435. $this->Mail->parseAddresses(
  1436. 'Joe User <joe@example.com>',
  1437. false
  1438. ),
  1439. 'Failed to recognise single address'
  1440. );
  1441. //Test quoted name IMAP
  1442. $this->assertNotEmpty(
  1443. $this->Mail->parseAddresses(
  1444. 'Tim "The Book" O\'Reilly <foo@example.com>'
  1445. ),
  1446. 'Failed to recognise quoted name (IMAP)'
  1447. );
  1448. //Test quoted name
  1449. $this->assertNotEmpty(
  1450. $this->Mail->parseAddresses(
  1451. 'Tim "The Book" O\'Reilly <foo@example.com>',
  1452. false
  1453. ),
  1454. 'Failed to recognise quoted name'
  1455. );
  1456. //Test single address IMAP
  1457. $this->assertNotEmpty(
  1458. $this->Mail->parseAddresses(
  1459. 'Joe User <joe@example.com>'
  1460. ),
  1461. 'Failed to recognise single address (IMAP)'
  1462. );
  1463. //Test unnamed address
  1464. $this->assertNotEmpty(
  1465. $this->Mail->parseAddresses(
  1466. 'joe@example.com',
  1467. false
  1468. ),
  1469. 'Failed to recognise unnamed address'
  1470. );
  1471. //Test unnamed address IMAP
  1472. $this->assertNotEmpty(
  1473. $this->Mail->parseAddresses(
  1474. 'joe@example.com'
  1475. ),
  1476. 'Failed to recognise unnamed address (IMAP)'
  1477. );
  1478. //Test invalid addresses
  1479. $this->assertEmpty(
  1480. $this->Mail->parseAddresses(
  1481. 'Joe User <joe@example.com.>, Jill User <jill.@example.net>'
  1482. ),
  1483. 'Failed to recognise invalid addresses (IMAP)'
  1484. );
  1485. //Test invalid addresses
  1486. $this->assertEmpty(
  1487. $this->Mail->parseAddresses(
  1488. 'Joe User <joe@example.com.>, Jill User <jill.@example.net>',
  1489. false
  1490. ),
  1491. 'Failed to recognise invalid addresses'
  1492. );
  1493. }
  1494.  
  1495. /**
  1496. * Test address escaping.
  1497. */
  1498. public function testAddressEscaping()
  1499. {
  1500. $this->Mail->Subject .= ': Address escaping';
  1501. $this->Mail->clearAddresses();
  1502. $this->Mail->addAddress('foo@example.com', 'Tim "The Book" O\'Reilly');
  1503. $this->Mail->Body = 'Test correct escaping of quotes in addresses.';
  1504. $this->buildBody();
  1505. $this->Mail->preSend();
  1506. $b = $this->Mail->getSentMIMEMessage();
  1507. $this->assertTrue((strpos($b, 'To: "Tim \"The Book\" O\'Reilly" <foo@example.com>') !== false));
  1508. }
  1509.  
  1510. /**
  1511. * Test BCC-only addressing.
  1512. */
  1513. public function testBCCAddressing()
  1514. {
  1515. $this->Mail->Subject .= ': BCC-only addressing';
  1516. $this->buildBody();
  1517. $this->Mail->clearAllRecipients();
  1518. $this->assertTrue($this->Mail->addBCC('a@example.com'), 'BCC addressing failed');
  1519. $this->assertTrue($this->Mail->send(), 'send failed');
  1520. }
  1521.  
  1522. /**
  1523. * Encoding and charset tests.
  1524. */
  1525. public function testEncodings()
  1526. {
  1527. $this->Mail->CharSet = 'iso-8859-1';
  1528. $this->assertEquals(
  1529. '=A1Hola!_Se=F1or!',
  1530. $this->Mail->encodeQ("\xa1Hola! Se\xf1or!", 'text'),
  1531. 'Q Encoding (text) failed'
  1532. );
  1533. $this->assertEquals(
  1534. '=A1Hola!_Se=F1or!',
  1535. $this->Mail->encodeQ("\xa1Hola! Se\xf1or!", 'comment'),
  1536. 'Q Encoding (comment) failed'
  1537. );
  1538. $this->assertEquals(
  1539. '=A1Hola!_Se=F1or!',
  1540. $this->Mail->encodeQ("\xa1Hola! Se\xf1or!", 'phrase'),
  1541. 'Q Encoding (phrase) failed'
  1542. );
  1543. $this->Mail->CharSet = 'UTF-8';
  1544. $this->assertEquals(
  1545. '=C2=A1Hola!_Se=C3=B1or!',
  1546. $this->Mail->encodeQ("\xc2\xa1Hola! Se\xc3\xb1or!", 'text'),
  1547. 'Q Encoding (text) failed'
  1548. );
  1549. //Strings containing '=' are a special case
  1550. $this->assertEquals(
  1551. 'Nov=C3=A1=3D',
  1552. $this->Mail->encodeQ("Nov\xc3\xa1=", 'text'),
  1553. 'Q Encoding (text) failed 2'
  1554. );
  1555. }
  1556.  
  1557. /**
  1558. * Test base-64 encoding.
  1559. */
  1560. public function testBase64()
  1561. {
  1562. $this->Mail->Subject .= ': Base-64 encoding';
  1563. $this->Mail->Encoding = 'base64';
  1564. $this->buildBody();
  1565. $this->assertTrue($this->Mail->send(), 'Base64 encoding failed');
  1566. }
  1567. /**
  1568. * S/MIME Signing tests (self-signed).
  1569. * @requires extension openssl
  1570. */
  1571. public function testSigning()
  1572. {
  1573. $this->Mail->Subject .= ': S/MIME signing';
  1574. $this->Mail->Body = 'This message is S/MIME signed.';
  1575. $this->buildBody();
  1576.  
  1577. $dn = array(
  1578. 'countryName' => 'UK',
  1579. 'stateOrProvinceName' => 'Here',
  1580. 'localityName' => 'There',
  1581. 'organizationName' => 'PHP',
  1582. 'organizationalUnitName' => 'PHPMailer',
  1583. 'commonName' => 'PHPMailer Test',
  1584. 'emailAddress' => 'phpmailer@example.com'
  1585. );
  1586. $keyconfig = array(
  1587. "digest_alg" => "sha256",
  1588. "private_key_bits" => 2048,
  1589. "private_key_type" => OPENSSL_KEYTYPE_RSA,
  1590. );
  1591. $password = 'password';
  1592. $certfile = 'certfile.txt';
  1593. $keyfile = 'keyfile.txt';
  1594.  
  1595. //Make a new key pair
  1596. $pk = openssl_pkey_new($keyconfig);
  1597. //Create a certificate signing request
  1598. $csr = openssl_csr_new($dn, $pk);
  1599. //Create a self-signed cert
  1600. $cert = openssl_csr_sign($csr, null, $pk, 1);
  1601. //Save the cert
  1602. openssl_x509_export($cert, $certout);
  1603. file_put_contents($certfile, $certout);
  1604. //Save the key
  1605. openssl_pkey_export($pk, $pkeyout, $password);
  1606. file_put_contents($keyfile, $pkeyout);
  1607.  
  1608. $this->Mail->sign(
  1609. $certfile,
  1610. $keyfile,
  1611. $password
  1612. );
  1613. $this->assertTrue($this->Mail->send(), 'S/MIME signing failed');
  1614.  
  1615. $msg = $this->Mail->getSentMIMEMessage();
  1616. $this->assertNotContains("\r\n\r\nMIME-Version:", $msg, 'Incorrect MIME headers');
  1617. unlink($certfile);
  1618. unlink($keyfile);
  1619. }
  1620.  
  1621. /**
  1622. * S/MIME Signing tests using a CA chain cert.
  1623. * To test that a generated message is signed correctly, save the message in a file
  1624. * and use openssl along with the certs generated by this script:
  1625. * `openssl smime -verify -in signed.eml -signer certfile.pem -CAfile cacertfile.pem`
  1626. * @requires extension openssl
  1627. */
  1628. public function testSigningWithCA()
  1629. {
  1630. $this->Mail->Subject .= ': S/MIME signing with CA';
  1631. $this->Mail->Body = 'This message is S/MIME signed with an extra CA cert.';
  1632. $this->buildBody();
  1633.  
  1634. $certprops = array(
  1635. 'countryName' => 'UK',
  1636. 'stateOrProvinceName' => 'Here',
  1637. 'localityName' => 'There',
  1638. 'organizationName' => 'PHP',
  1639. 'organizationalUnitName' => 'PHPMailer',
  1640. 'commonName' => 'PHPMailer Test',
  1641. 'emailAddress' => 'phpmailer@example.com'
  1642. );
  1643. $cacertprops = array(
  1644. 'countryName' => 'UK',
  1645. 'stateOrProvinceName' => 'Here',
  1646. 'localityName' => 'There',
  1647. 'organizationName' => 'PHP',
  1648. 'organizationalUnitName' => 'PHPMailer CA',
  1649. 'commonName' => 'PHPMailer Test CA',
  1650. 'emailAddress' => 'phpmailer@example.com'
  1651. );
  1652. $keyconfig = array(
  1653. "digest_alg" => "sha256",
  1654. "private_key_bits" => 2048,
  1655. "private_key_type" => OPENSSL_KEYTYPE_RSA,
  1656. );
  1657. $password = 'password';
  1658. $cacertfile = 'cacertfile.pem';
  1659. $cakeyfile = 'cakeyfile.pem';
  1660. $certfile = 'certfile.pem';
  1661. $keyfile = 'keyfile.pem';
  1662.  
  1663. //Create a CA cert
  1664. //Make a new key pair
  1665. $capk = openssl_pkey_new($keyconfig);
  1666. //Create a certificate signing request
  1667. $csr = openssl_csr_new($cacertprops, $capk);
  1668. //Create a self-signed cert
  1669. $cert = openssl_csr_sign($csr, null, $capk, 1);
  1670. //Save the CA cert
  1671. openssl_x509_export($cert, $certout);
  1672. file_put_contents($cacertfile, $certout);
  1673. //Save the CA key
  1674. openssl_pkey_export($capk, $pkeyout, $password);
  1675. file_put_contents($cakeyfile, $pkeyout);
  1676.  
  1677. //Create a cert signed by our CA
  1678. //Make a new key pair
  1679. $pk = openssl_pkey_new($keyconfig);
  1680. //Create a certificate signing request
  1681. $csr = openssl_csr_new($certprops, $pk);
  1682. //Create a self-signed cert
  1683. $cert = openssl_csr_sign($csr, 'file://' . $cacertfile, $capk, 1);
  1684. //Save the cert
  1685. openssl_x509_export($cert, $certout);
  1686. file_put_contents($certfile, $certout);
  1687. //Save the key
  1688. openssl_pkey_export($pk, $pkeyout, $password);
  1689. file_put_contents($keyfile, $pkeyout);
  1690.  
  1691. $this->Mail->sign(
  1692. $certfile,
  1693. $keyfile,
  1694. $password,
  1695. $cacertfile
  1696. );
  1697. $this->assertTrue($this->Mail->send(), 'S/MIME signing with CA failed');
  1698. unlink($cacertfile);
  1699. unlink($cakeyfile);
  1700. unlink($certfile);
  1701. unlink($keyfile);
  1702. }
  1703.  
  1704. /**
  1705. * DKIM Signing tests.
  1706. * @requires extension openssl
  1707. */
  1708. public function testDKIM()
  1709. {
  1710. $this->Mail->Subject .= ': DKIM signing';
  1711. $this->Mail->Body = 'This message is DKIM signed.';
  1712. $this->buildBody();
  1713. $privatekeyfile = 'dkim_private.key';
  1714. //Make a new key pair
  1715. //(2048 bits is the recommended minimum key length -
  1716. //gmail won't accept less than 1024 bits)
  1717. $pk = openssl_pkey_new(
  1718. array(
  1719. 'private_key_bits' => 2048,
  1720. 'private_key_type' => OPENSSL_KEYTYPE_RSA
  1721. )
  1722. );
  1723. openssl_pkey_export_to_file($pk, $privatekeyfile);
  1724. $this->Mail->DKIM_domain = 'example.com';
  1725. $this->Mail->DKIM_private = $privatekeyfile;
  1726. $this->Mail->DKIM_selector = 'phpmailer';
  1727. $this->Mail->DKIM_passphrase = ''; //key is not encrypted
  1728. $this->assertTrue($this->Mail->send(), 'DKIM signed mail failed');
  1729. unlink($privatekeyfile);
  1730. }
  1731.  
  1732. /**
  1733. * Test line break reformatting.
  1734. */
  1735. public function testLineBreaks()
  1736. {
  1737. $unixsrc = "hello\nWorld\nAgain\n";
  1738. $macsrc = "hello\rWorld\rAgain\r";
  1739. $windowssrc = "hello\r\nWorld\r\nAgain\r\n";
  1740. $mixedsrc = "hello\nWorld\rAgain\r\n";
  1741. $target = "hello\r\nWorld\r\nAgain\r\n";
  1742. $this->assertEquals($target, PHPMailer::normalizeBreaks($unixsrc), 'UNIX break reformatting failed');
  1743. $this->assertEquals($target, PHPMailer::normalizeBreaks($macsrc), 'Mac break reformatting failed');
  1744. $this->assertEquals($target, PHPMailer::normalizeBreaks($windowssrc), 'Windows break reformatting failed');
  1745. $this->assertEquals($target, PHPMailer::normalizeBreaks($mixedsrc), 'Mixed break reformatting failed');
  1746. }
  1747.  
  1748. /**
  1749. * Test line length detection
  1750. */
  1751. public function testLineLength()
  1752. {
  1753. $oklen = str_repeat(str_repeat('0', PHPMailer::MAX_LINE_LENGTH)."\r\n", 10);
  1754. $badlen = str_repeat(str_repeat('1', PHPMailer::MAX_LINE_LENGTH + 1) . "\r\n", 2);
  1755. $this->assertTrue(PHPMailer::hasLineLongerThanMax($badlen), 'Long line not detected (only)');
  1756. $this->assertTrue(PHPMailer::hasLineLongerThanMax($oklen . $badlen), 'Long line not detected (first)');
  1757. $this->assertTrue(PHPMailer::hasLineLongerThanMax($badlen . $oklen), 'Long line not detected (last)');
  1758. $this->assertTrue(
  1759. PHPMailer::hasLineLongerThanMax($oklen . $badlen . $oklen),
  1760. 'Long line not detected (middle)'
  1761. );
  1762. $this->assertFalse(PHPMailer::hasLineLongerThanMax($oklen), 'Long line false positive');
  1763. $this->Mail->isHTML(false);
  1764. $this->Mail->Subject .= ": Line length test";
  1765. $this->Mail->CharSet = 'UTF-8';
  1766. $this->Mail->Encoding = '8bit';
  1767. $this->Mail->Body = $oklen . $badlen . $oklen . $badlen;
  1768. $this->buildBody();
  1769. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1770. $this->assertEquals('quoted-printable', $this->Mail->Encoding, 'Long line did not override transfer encoding');
  1771. }
  1772.  
  1773. /**
  1774. * Test setting and retrieving message ID.
  1775. */
  1776. public function testMessageID()
  1777. {
  1778. $this->Mail->Body = 'Test message ID.';
  1779. $id = md5(12345);
  1780. $this->Mail->MessageID = $id;
  1781. $this->buildBody();
  1782. $this->Mail->preSend();
  1783. $lastid = $this->Mail->getLastMessageID();
  1784. $this->assertEquals($lastid, $id, 'Custom Message ID mismatch');
  1785. }
  1786.  
  1787. /**
  1788. * Miscellaneous calls to improve test coverage and some small tests.
  1789. */
  1790. public function testMiscellaneous()
  1791. {
  1792. $this->assertEquals('application/pdf', PHPMailer::_mime_types('pdf'), 'MIME TYPE lookup failed');
  1793. $this->Mail->addCustomHeader('SomeHeader: Some Value');
  1794. $this->Mail->clearCustomHeaders();
  1795. $this->Mail->clearAttachments();
  1796. $this->Mail->isHTML(false);
  1797. $this->Mail->isSMTP();
  1798. $this->Mail->isMail();
  1799. $this->Mail->isSendmail();
  1800. $this->Mail->isQmail();
  1801. $this->Mail->setLanguage('fr');
  1802. $this->Mail->Sender = '';
  1803. $this->Mail->createHeader();
  1804. $this->assertFalse($this->Mail->set('x', 'y'), 'Invalid property set succeeded');
  1805. $this->assertTrue($this->Mail->set('Timeout', 11), 'Valid property set failed');
  1806. $this->assertTrue($this->Mail->set('AllowEmpty', null), 'Null property set failed');
  1807. $this->assertTrue($this->Mail->set('AllowEmpty', false), 'Valid property set of null property failed');
  1808. //Test pathinfo
  1809. $a = '/mnt/files/飛兒樂 團光茫.mp3';
  1810. $q = PHPMailer::mb_pathinfo($a);
  1811. $this->assertEquals($q['dirname'], '/mnt/files', 'UNIX dirname not matched');
  1812. $this->assertEquals($q['basename'], '飛兒樂 團光茫.mp3', 'UNIX basename not matched');
  1813. $this->assertEquals($q['extension'], 'mp3', 'UNIX extension not matched');
  1814. $this->assertEquals($q['filename'], '飛兒樂 團光茫', 'UNIX filename not matched');
  1815. $this->assertEquals(
  1816. PHPMailer::mb_pathinfo($a, PATHINFO_DIRNAME),
  1817. '/mnt/files',
  1818. 'Dirname path element not matched'
  1819. );
  1820. $this->assertEquals(PHPMailer::mb_pathinfo($a, 'filename'), '飛兒樂 團光茫', 'Filename path element not matched');
  1821. $a = 'c:\mnt\files\飛兒樂 團光茫.mp3';
  1822. $q = PHPMailer::mb_pathinfo($a);
  1823. $this->assertEquals($q['dirname'], 'c:\mnt\files', 'Windows dirname not matched');
  1824. $this->assertEquals($q['basename'], '飛兒樂 團光茫.mp3', 'Windows basename not matched');
  1825. $this->assertEquals($q['extension'], 'mp3', 'Windows extension not matched');
  1826. $this->assertEquals($q['filename'], '飛兒樂 團光茫', 'Windows filename not matched');
  1827. }
  1828. public function testBadSMTP()
  1829. {
  1830. $this->Mail->smtpConnect();
  1831. $smtp = $this->Mail->getSMTPInstance();
  1832. $this->assertFalse($smtp->mail("somewhere\nbad"), 'Bad SMTP command containing breaks accepted');
  1833. }
  1834.  
  1835. /**
  1836. * Tests the Custom header getter
  1837. */
  1838. public function testCustomHeaderGetter()
  1839. {
  1840. $this->Mail->addCustomHeader('foo', 'bar');
  1841. $this->assertEquals(array(array('foo', 'bar')), $this->Mail->getCustomHeaders());
  1842.  
  1843. $this->Mail->addCustomHeader('foo', 'baz');
  1844. $this->assertEquals(array(
  1845. array('foo', 'bar'),
  1846. array('foo', 'baz')
  1847. ), $this->Mail->getCustomHeaders());
  1848.  
  1849. $this->Mail->clearCustomHeaders();
  1850. $this->assertEmpty($this->Mail->getCustomHeaders());
  1851.  
  1852. $this->Mail->addCustomHeader('yux');
  1853. $this->assertEquals(array(array('yux')), $this->Mail->getCustomHeaders());
  1854.  
  1855. $this->Mail->addCustomHeader('Content-Type: application/json');
  1856. $this->assertEquals(array(
  1857. array('yux'),
  1858. array('Content-Type', ' application/json')
  1859. ), $this->Mail->getCustomHeaders());
  1860. }
  1861.  
  1862. /**
  1863. * Tests setting and retrieving ConfirmReadingTo address, also known as "read receipt" address.
  1864. */
  1865. public function testConfirmReadingTo()
  1866. {
  1867. $this->Mail->CharSet = 'utf-8';
  1868. $this->buildBody();
  1869.  
  1870. $this->Mail->ConfirmReadingTo = 'test@example..com'; //Invalid address
  1871. $this->assertFalse($this->Mail->send(), $this->Mail->ErrorInfo);
  1872.  
  1873. $this->Mail->ConfirmReadingTo = ' test@example.com'; //Extra space to trim
  1874. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1875. $this->assertEquals(
  1876. 'test@example.com',
  1877. $this->Mail->ConfirmReadingTo,
  1878. 'Unexpected read receipt address');
  1879.  
  1880. $this->Mail->ConfirmReadingTo = 'test@françois.ch'; //Address with IDN
  1881. if ($this->Mail->idnSupported()) {
  1882. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1883. $this->assertEquals(
  1884. 'test@xn--franois-xxa.ch',
  1885. $this->Mail->ConfirmReadingTo,
  1886. 'IDN address not converted to punycode');
  1887. } else {
  1888. $this->assertFalse($this->Mail->send(), $this->Mail->ErrorInfo);
  1889. }
  1890. }
  1891.  
  1892. /**
  1893. * Tests CharSet and Unicode -> ASCII conversions for addresses with IDN.
  1894. */
  1895. public function testConvertEncoding()
  1896. {
  1897. if (!$this->Mail->idnSupported()) {
  1898. $this->markTestSkipped('intl and/or mbstring extensions are not available');
  1899. }
  1900.  
  1901. $this->Mail->clearAllRecipients();
  1902. $this->Mail->clearReplyTos();
  1903.  
  1904. // This file is UTF-8 encoded. Create a domain encoded in "iso-8859-1".
  1905. $domain = '@' . mb_convert_encoding('françois.ch', 'ISO-8859-1', 'UTF-8');
  1906. $this->Mail->addAddress('test' . $domain);
  1907. $this->Mail->addCC('test+cc' . $domain);
  1908. $this->Mail->addBCC('test+bcc' . $domain);
  1909. $this->Mail->addReplyTo('test+replyto' . $domain);
  1910.  
  1911. // Queued addresses are not returned by get*Addresses() before send() call.
  1912. $this->assertEmpty($this->Mail->getToAddresses(), 'Bad "to" recipients');
  1913. $this->assertEmpty($this->Mail->getCcAddresses(), 'Bad "cc" recipients');
  1914. $this->assertEmpty($this->Mail->getBccAddresses(), 'Bad "bcc" recipients');
  1915. $this->assertEmpty($this->Mail->getReplyToAddresses(), 'Bad "reply-to" recipients');
  1916.  
  1917. // Clear queued BCC recipient.
  1918. $this->Mail->clearBCCs();
  1919.  
  1920. $this->buildBody();
  1921. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1922.  
  1923. // Addresses with IDN are returned by get*Addresses() after send() call.
  1924. $domain = $this->Mail->punyencodeAddress($domain);
  1925. $this->assertEquals(
  1926. array(array('test' . $domain, '')),
  1927. $this->Mail->getToAddresses(),
  1928. 'Bad "to" recipients');
  1929. $this->assertEquals(
  1930. array(array('test+cc' . $domain, '')),
  1931. $this->Mail->getCcAddresses(),
  1932. 'Bad "cc" recipients');
  1933. $this->assertEmpty($this->Mail->getBccAddresses(), 'Bad "bcc" recipients');
  1934. $this->assertEquals(
  1935. array('test+replyto' . $domain => array('test+replyto' . $domain, '')),
  1936. $this->Mail->getReplyToAddresses(),
  1937. 'Bad "reply-to" addresses');
  1938. }
  1939.  
  1940. /**
  1941. * Tests removal of duplicate recipients and reply-tos.
  1942. */
  1943. public function testDuplicateIDNRemoved()
  1944. {
  1945. if (!$this->Mail->idnSupported()) {
  1946. $this->markTestSkipped('intl and/or mbstring extensions are not available');
  1947. }
  1948.  
  1949. $this->Mail->clearAllRecipients();
  1950. $this->Mail->clearReplyTos();
  1951.  
  1952. $this->Mail->CharSet = 'utf-8';
  1953.  
  1954. $this->assertTrue($this->Mail->addAddress('test@françois.ch'));
  1955. $this->assertFalse($this->Mail->addAddress('test@françois.ch'));
  1956. $this->assertTrue($this->Mail->addAddress('test@FRANÇOIS.CH'));
  1957. $this->assertFalse($this->Mail->addAddress('test@FRANÇOIS.CH'));
  1958. $this->assertTrue($this->Mail->addAddress('test@xn--franois-xxa.ch'));
  1959. $this->assertFalse($this->Mail->addAddress('test@xn--franois-xxa.ch'));
  1960. $this->assertFalse($this->Mail->addAddress('test@XN--FRANOIS-XXA.CH'));
  1961.  
  1962. $this->assertTrue($this->Mail->addReplyTo('test+replyto@françois.ch'));
  1963. $this->assertFalse($this->Mail->addReplyTo('test+replyto@françois.ch'));
  1964. $this->assertTrue($this->Mail->addReplyTo('test+replyto@FRANÇOIS.CH'));
  1965. $this->assertFalse($this->Mail->addReplyTo('test+replyto@FRANÇOIS.CH'));
  1966. $this->assertTrue($this->Mail->addReplyTo('test+replyto@xn--franois-xxa.ch'));
  1967. $this->assertFalse($this->Mail->addReplyTo('test+replyto@xn--franois-xxa.ch'));
  1968. $this->assertFalse($this->Mail->addReplyTo('test+replyto@XN--FRANOIS-XXA.CH'));
  1969.  
  1970. $this->buildBody();
  1971. $this->assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
  1972.  
  1973. // There should be only one "To" address and one "Reply-To" address.
  1974. $this->assertEquals(
  1975. 1,
  1976. count($this->Mail->getToAddresses()),
  1977. 'Bad count of "to" recipients');
  1978. $this->assertEquals(
  1979. 1,
  1980. count($this->Mail->getReplyToAddresses()),
  1981. 'Bad count of "reply-to" addresses');
  1982. }
  1983.  
  1984. /**
  1985. * Use a fake POP3 server to test POP-before-SMTP auth.
  1986. * With a known-good login
  1987. */
  1988. public function testPopBeforeSmtpGood()
  1989. {
  1990. //Start a fake POP server
  1991. $pid = shell_exec('nohup ./runfakepopserver.sh >/dev/null 2>/dev/null & printf "%u" $!');
  1992. $this->pids[] = $pid;
  1993.  
  1994. sleep(2);
  1995. //Test a known-good login
  1996. $this->assertTrue(
  1997. POP3::popBeforeSmtp('localhost', 1100, 10, 'user', 'test', $this->Mail->SMTPDebug),
  1998. 'POP before SMTP failed'
  1999. );
  2000. //Kill the fake server
  2001. shell_exec('kill -TERM ' . escapeshellarg($pid));
  2002. sleep(2);
  2003. }
  2004.  
  2005. /**
  2006. * Use a fake POP3 server to test POP-before-SMTP auth.
  2007. * With a known-bad login
  2008. */
  2009. public function testPopBeforeSmtpBad()
  2010. {
  2011. //Start a fake POP server on a different port
  2012. //so we don't inadvertently connect to the previous instance
  2013. $pid = shell_exec('nohup ./runfakepopserver.sh 1101 >/dev/null 2>/dev/null & printf "%u" $!');
  2014. $this->pids[] = $pid;
  2015.  
  2016. sleep(2);
  2017. //Test a known-bad login
  2018. $this->assertFalse(
  2019. POP3::popBeforeSmtp('localhost', 1101, 10, 'user', 'xxx', $this->Mail->SMTPDebug),
  2020. 'POP before SMTP should have failed'
  2021. );
  2022. shell_exec('kill -TERM ' . escapeshellarg($pid));
  2023. sleep(2);
  2024. }
  2025.  
  2026. /**
  2027. * Test SMTP host connections.
  2028. * This test can take a long time, so run it last
  2029. */
  2030. public function testSmtpConnect()
  2031. {
  2032. $this->Mail->SMTPDebug = 4; //Show connection-level errors
  2033. $this->assertTrue($this->Mail->smtpConnect(), 'SMTP single connect failed');
  2034. $this->Mail->smtpClose();
  2035. $this->Mail->Host = "ssl://localhost:12345;tls://localhost:587;10.10.10.10:54321;localhost:12345;10.10.10.10";
  2036. $this->assertFalse($this->Mail->smtpConnect(), 'SMTP bad multi-connect succeeded');
  2037. $this->Mail->smtpClose();
  2038. $this->Mail->Host = "localhost:12345;10.10.10.10:54321;" . $_REQUEST['mail_host'];
  2039. $this->assertTrue($this->Mail->smtpConnect(), 'SMTP multi-connect failed');
  2040. $this->Mail->smtpClose();
  2041. $this->Mail->Host = " localhost:12345 ; " . $_REQUEST['mail_host'] . ' ';
  2042. $this->assertTrue($this->Mail->smtpConnect(), 'SMTP hosts with stray spaces failed');
  2043. $this->Mail->smtpClose();
  2044. $this->Mail->Host = $_REQUEST['mail_host'];
  2045. //Need to pick a harmless option so as not cause problems of its own! socket:bind doesn't work with Travis-CI
  2046. $this->assertTrue(
  2047. $this->Mail->smtpConnect(array('ssl' => array('verify_depth' => 10))),
  2048. 'SMTP connect with options failed'
  2049. );
  2050. }
  2051. }
  2052.  
  2053. /**
  2054. * This is a sample form for setting appropriate test values through a browser
  2055. * These values can also be set using a file called testbootstrap.php (not in repo) in the same folder as this script
  2056. * which is probably more useful if you run these tests a lot
  2057. * <html>
  2058. * <body>
  2059. * <h3>phpmailer Unit Test</h3>
  2060. * By entering a SMTP hostname it will automatically perform tests with SMTP.
  2061. *
  2062. * <form name="phpmailer_unit" action=__FILE__ method="get">
  2063. * <input type="hidden" name="submitted" value="1"/>
  2064. * From Address: <input type="text" size="50" name="mail_from" value="<?php echo get("mail_from"); ?>"/>
  2065. * <br/>
  2066. * To Address: <input type="text" size="50" name="mail_to" value="<?php echo get("mail_to"); ?>"/>
  2067. * <br/>
  2068. * Cc Address: <input type="text" size="50" name="mail_cc" value="<?php echo get("mail_cc"); ?>"/>
  2069. * <br/>
  2070. * SMTP Hostname: <input type="text" size="50" name="mail_host" value="<?php echo get("mail_host"); ?>"/>
  2071. * <p/>
  2072. * <input type="submit" value="Run Test"/>
  2073. *
  2074. * </form>
  2075. * </body>
  2076. * </html>
  2077. */