phpmailerTest.php 81 KB

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