Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ignitetch
GitHub Repository: ignitetch/advphishing
Path: blob/master/PHPMailer/test/PHPMailerTest.php
738 views
1
<?php
2
/**
3
* PHPMailer - PHP email transport unit tests.
4
* PHP version 5.5.
5
*
6
* @author Marcus Bointon <[email protected]>
7
* @author Andy Prevost
8
* @copyright 2012 - 2020 Marcus Bointon
9
* @copyright 2004 - 2009 Andy Prevost
10
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
11
*/
12
13
namespace PHPMailer\Test;
14
15
use PHPMailer\PHPMailer\Exception;
16
use PHPMailer\PHPMailer\OAuth;
17
use PHPMailer\PHPMailer\PHPMailer;
18
use PHPMailer\PHPMailer\POP3;
19
use PHPMailer\PHPMailer\SMTP;
20
use PHPUnit\Framework\TestCase;
21
22
/**
23
* PHPMailer - PHP email transport unit test class.
24
*/
25
final class PHPMailerTest extends TestCase
26
{
27
/**
28
* Holds the PHPMailer instance.
29
*
30
* @var PHPMailer
31
*/
32
private $Mail;
33
34
/**
35
* Holds the SMTP mail host.
36
*
37
* @var string
38
*/
39
private $Host = '';
40
41
/**
42
* Holds the change log.
43
*
44
* @var string[]
45
*/
46
private $ChangeLog = [];
47
48
/**
49
* Holds the note log.
50
*
51
* @var string[]
52
*/
53
private $NoteLog = [];
54
55
/**
56
* Default include path.
57
*
58
* @var string
59
*/
60
private $INCLUDE_DIR = '..';
61
62
/**
63
* PIDs of any processes we need to kill.
64
*
65
* @var array
66
*/
67
private $pids = [];
68
69
/**
70
* Run before each test is started.
71
*/
72
protected function setUp()
73
{
74
$this->INCLUDE_DIR = dirname(__DIR__); //Default to the dir above the test dir, i.e. the project home dir
75
if (file_exists($this->INCLUDE_DIR . '/test/testbootstrap.php')) {
76
include $this->INCLUDE_DIR . '/test/testbootstrap.php'; //Overrides go in here
77
}
78
$this->Mail = new PHPMailer();
79
$this->Mail->SMTPDebug = SMTP::DEBUG_CONNECTION; //Full debug output
80
$this->Mail->Debugoutput = ['PHPMailer\Test\DebugLogTestListener', 'debugLog'];
81
$this->Mail->Priority = 3;
82
$this->Mail->Encoding = '8bit';
83
$this->Mail->CharSet = PHPMailer::CHARSET_ISO88591;
84
if (array_key_exists('mail_from', $_REQUEST)) {
85
$this->Mail->From = $_REQUEST['mail_from'];
86
} else {
87
$this->Mail->From = '[email protected]';
88
}
89
$this->Mail->FromName = 'Unit Tester';
90
$this->Mail->Sender = '';
91
$this->Mail->Subject = 'Unit Test';
92
$this->Mail->Body = '';
93
$this->Mail->AltBody = '';
94
$this->Mail->WordWrap = 0;
95
if (array_key_exists('mail_host', $_REQUEST)) {
96
$this->Mail->Host = $_REQUEST['mail_host'];
97
} else {
98
$this->Mail->Host = 'mail.example.com';
99
}
100
if (array_key_exists('mail_port', $_REQUEST)) {
101
$this->Mail->Port = $_REQUEST['mail_port'];
102
} else {
103
$this->Mail->Port = 25;
104
}
105
$this->Mail->Helo = 'localhost.localdomain';
106
$this->Mail->SMTPAuth = false;
107
$this->Mail->Username = '';
108
$this->Mail->Password = '';
109
if (array_key_exists('mail_useauth', $_REQUEST)) {
110
$this->Mail->SMTPAuth = $_REQUEST['mail_useauth'];
111
}
112
if (array_key_exists('mail_username', $_REQUEST)) {
113
$this->Mail->Username = $_REQUEST['mail_username'];
114
}
115
if (array_key_exists('mail_userpass', $_REQUEST)) {
116
$this->Mail->Password = $_REQUEST['mail_userpass'];
117
}
118
$this->Mail->addReplyTo('[email protected]', 'Reply Guy');
119
$this->Mail->Sender = '[email protected]';
120
if ($this->Mail->Host != '') {
121
$this->Mail->isSMTP();
122
} else {
123
$this->Mail->isMail();
124
}
125
if (array_key_exists('mail_to', $_REQUEST)) {
126
$this->setAddress($_REQUEST['mail_to'], 'Test User', 'to');
127
}
128
if (array_key_exists('mail_cc', $_REQUEST) && $_REQUEST['mail_cc'] !== '') {
129
$this->setAddress($_REQUEST['mail_cc'], 'Carbon User', 'cc');
130
}
131
}
132
133
/**
134
* Run after each test is completed.
135
*/
136
protected function tearDown()
137
{
138
// Clean global variables
139
$this->Mail = null;
140
$this->ChangeLog = [];
141
$this->NoteLog = [];
142
143
foreach ($this->pids as $pid) {
144
$p = escapeshellarg($pid);
145
shell_exec("ps $p && kill -TERM $p");
146
}
147
}
148
149
/**
150
* Build the body of the message in the appropriate format.
151
*/
152
private function buildBody()
153
{
154
$this->checkChanges();
155
156
// Determine line endings for message
157
if ('text/html' === $this->Mail->ContentType || $this->Mail->AltBody !== '') {
158
$eol = "<br>\r\n";
159
$bullet_start = '<li>';
160
$bullet_end = "</li>\r\n";
161
$list_start = "<ul>\r\n";
162
$list_end = "</ul>\r\n";
163
} else {
164
$eol = "\r\n";
165
$bullet_start = ' - ';
166
$bullet_end = "\r\n";
167
$list_start = '';
168
$list_end = '';
169
}
170
171
$ReportBody = '';
172
173
$ReportBody .= '---------------------' . $eol;
174
$ReportBody .= 'Unit Test Information' . $eol;
175
$ReportBody .= '---------------------' . $eol;
176
$ReportBody .= 'phpmailer version: ' . PHPMailer::VERSION . $eol;
177
$ReportBody .= 'Content Type: ' . $this->Mail->ContentType . $eol;
178
$ReportBody .= 'CharSet: ' . $this->Mail->CharSet . $eol;
179
180
if ($this->Mail->Host !== '') {
181
$ReportBody .= 'Host: ' . $this->Mail->Host . $eol;
182
}
183
184
// If attachments then create an attachment list
185
$attachments = $this->Mail->getAttachments();
186
if (count($attachments) > 0) {
187
$ReportBody .= 'Attachments:' . $eol;
188
$ReportBody .= $list_start;
189
foreach ($attachments as $attachment) {
190
$ReportBody .= $bullet_start . 'Name: ' . $attachment[1] . ', ';
191
$ReportBody .= 'Encoding: ' . $attachment[3] . ', ';
192
$ReportBody .= 'Type: ' . $attachment[4] . $bullet_end;
193
}
194
$ReportBody .= $list_end . $eol;
195
}
196
197
// If there are changes then list them
198
if (count($this->ChangeLog) > 0) {
199
$ReportBody .= 'Changes' . $eol;
200
$ReportBody .= '-------' . $eol;
201
202
$ReportBody .= $list_start;
203
foreach ($this->ChangeLog as $iValue) {
204
$ReportBody .= $bullet_start . $iValue[0] . ' was changed to [' .
205
$iValue[1] . ']' . $bullet_end;
206
}
207
$ReportBody .= $list_end . $eol . $eol;
208
}
209
210
// If there are notes then list them
211
if (count($this->NoteLog) > 0) {
212
$ReportBody .= 'Notes' . $eol;
213
$ReportBody .= '-----' . $eol;
214
215
$ReportBody .= $list_start;
216
foreach ($this->NoteLog as $iValue) {
217
$ReportBody .= $bullet_start . $iValue . $bullet_end;
218
}
219
$ReportBody .= $list_end;
220
}
221
222
// Re-attach the original body
223
$this->Mail->Body .= $eol . $ReportBody;
224
}
225
226
/**
227
* Check which default settings have been changed for the report.
228
*/
229
private function checkChanges()
230
{
231
if (3 != $this->Mail->Priority) {
232
$this->addChange('Priority', $this->Mail->Priority);
233
}
234
if (PHPMailer::ENCODING_8BIT !== $this->Mail->Encoding) {
235
$this->addChange('Encoding', $this->Mail->Encoding);
236
}
237
if (PHPMailer::CHARSET_ISO88591 !== $this->Mail->CharSet) {
238
$this->addChange('CharSet', $this->Mail->CharSet);
239
}
240
if ('' != $this->Mail->Sender) {
241
$this->addChange('Sender', $this->Mail->Sender);
242
}
243
if (0 != $this->Mail->WordWrap) {
244
$this->addChange('WordWrap', $this->Mail->WordWrap);
245
}
246
if ('mail' !== $this->Mail->Mailer) {
247
$this->addChange('Mailer', $this->Mail->Mailer);
248
}
249
if (25 != $this->Mail->Port) {
250
$this->addChange('Port', $this->Mail->Port);
251
}
252
if ('localhost.localdomain' !== $this->Mail->Helo) {
253
$this->addChange('Helo', $this->Mail->Helo);
254
}
255
if ($this->Mail->SMTPAuth) {
256
$this->addChange('SMTPAuth', 'true');
257
}
258
}
259
260
/**
261
* Add a changelog entry.
262
*
263
* @param string $sName
264
* @param string $sNewValue
265
*/
266
private function addChange($sName, $sNewValue)
267
{
268
$this->ChangeLog[] = [$sName, $sNewValue];
269
}
270
271
/**
272
* Adds a simple note to the message.
273
*
274
* @param string $sValue
275
*/
276
private function addNote($sValue)
277
{
278
$this->NoteLog[] = $sValue;
279
}
280
281
/**
282
* Adds all of the addresses.
283
*
284
* @param string $sAddress
285
* @param string $sName
286
* @param string $sType
287
*
288
* @return bool
289
*/
290
private function setAddress($sAddress, $sName = '', $sType = 'to')
291
{
292
switch ($sType) {
293
case 'to':
294
return $this->Mail->addAddress($sAddress, $sName);
295
case 'cc':
296
return $this->Mail->addCC($sAddress, $sName);
297
case 'bcc':
298
return $this->Mail->addBCC($sAddress, $sName);
299
}
300
301
return false;
302
}
303
304
/**
305
* Check that we have loaded default test params.
306
* Pretty much everything will fail due to unset recipient if this is not done.
307
*/
308
public function testBootstrap()
309
{
310
self::assertFileExists(
311
$this->INCLUDE_DIR . '/test/testbootstrap.php',
312
'Test config params missing - copy testbootstrap.php to testbootstrap-dist.php and change as appropriate'
313
);
314
}
315
316
/**
317
* Test CRAM-MD5 authentication.
318
* Needs a connection to a server that supports this auth mechanism, so commented out by default.
319
*/
320
public function testAuthCRAMMD5()
321
{
322
$this->Mail->Host = 'hostname';
323
$this->Mail->Port = 587;
324
$this->Mail->SMTPAuth = true;
325
$this->Mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
326
$this->Mail->AuthType = 'CRAM-MD5';
327
$this->Mail->Username = 'username';
328
$this->Mail->Password = 'password';
329
$this->Mail->Body = 'Test body';
330
$this->Mail->Subject .= ': Auth CRAM-MD5';
331
$this->Mail->From = '[email protected]';
332
$this->Mail->Sender = '[email protected]';
333
$this->Mail->clearAllRecipients();
334
$this->Mail->addAddress('[email protected]');
335
//self::assertTrue($this->mail->send(), $this->mail->ErrorInfo);
336
}
337
338
/**
339
* Test email address validation.
340
* Test addresses obtained from http://isemail.info
341
* Some failing cases commented out that are apparently up for debate!
342
*/
343
public function testValidate()
344
{
345
$validaddresses = [
346
'[email protected]',
347
'[email protected]',
348
'1234567890123456789012345678901234567890123456789012345678901234@example.org',
349
'"first\"last"@example.org',
350
'"first@last"@example.org',
351
'"first\last"@example.org',
352
'first.last@[12.34.56.78]',
353
'first.last@x23456789012345678901234567890123456789012345678901234567890123.example.org',
354
'[email protected]',
355
'"first\last"@example.org',
356
'"Abc\@def"@example.org',
357
'"Fred\ Bloggs"@example.org',
358
'"Joe.\Blow"@example.org',
359
'"Abc@def"@example.org',
360
'[email protected]',
361
'customer/[email protected]',
362
'[email protected]',
363
'!def!xyz%[email protected]',
364
'[email protected]',
365
'[email protected]',
366
'[email protected]',
367
'[email protected]',
368
'[email protected]',
369
'[email protected]',
370
'[email protected]',
371
'[email protected]',
372
't*[email protected]',
373
'[email protected]',
374
'{_test_}@example.org',
375
'[email protected]',
376
'"test.test"@example.org',
377
'test."test"@example.org',
378
'"test@test"@example.org',
379
'[email protected]',
380
'test@[123.123.123.123]',
381
'[email protected]',
382
'[email protected]',
383
'"test\test"@example.org',
384
'"test\blah"@example.org',
385
'"test\blah"@example.org',
386
'"test\"blah"@example.org',
387
'customer/[email protected]',
388
'[email protected]',
389
'[email protected]',
390
'"Austin@Powers"@example.org',
391
'[email protected]',
392
'"Ima.Fool"@example.org',
393
'"first"."last"@example.org',
394
'"first".middle."last"@example.org',
395
'"first"[email protected]',
396
'first."last"@example.org',
397
'"first"."middle"."last"@example.org',
398
'"first.middle"."last"@example.org',
399
'"first.middle.last"@example.org',
400
'"first..last"@example.org',
401
'"first\"last"@example.org',
402
'first."mid\dle"."last"@example.org',
403
'[email protected]',
404
'[email protected]',
405
'aaa@[123.123.123.123]',
406
'[email protected]',
407
'[email protected]',
408
'[email protected]',
409
'[email protected]',
410
'[email protected]',
411
'[email protected]',
412
'"Joe\Blow"@example.org',
413
'user%[email protected]',
414
'cdburgess+!#$%&\'*-/=?+_{}|[email protected]',
415
'[email protected]',
416
'[email protected]',
417
'[email protected]',
418
];
419
//These are invalid according to PHP's filter_var
420
//which doesn't allow dotless domains, numeric TLDs or unbracketed IPv4 literals
421
$invalidphp = [
422
'a@b',
423
'a@bar',
424
'first.last@com',
425
'[email protected]',
426
'[email protected]',
427
'[email protected]',
428
];
429
//Valid RFC 5322 addresses using quoting and comments
430
//Note that these are *not* all valid for RFC5321
431
$validqandc = [
432
'HM2Kinsists@(that comments are allowed)this.is.ok',
433
'"Doug \"Ace\" L."@example.org',
434
'"[[ test ]]"@example.org',
435
'"Ima Fool"@example.org',
436
'"test blah"@example.org',
437
'(foo)cal(bar)@(baz)example.com(quux)',
438
'cal@example(woo).(yay)com',
439
'cal(woo(yay)hoopla)@example.com',
440
'cal(foo\@bar)@example.com',
441
'cal(foo\)bar)@example.com',
442
'first()[email protected]',
443
'pete(his account)@silly.test(his host)',
444
'c@(Chris\'s host.)public.example',
445
'jdoe@machine(comment). example',
446
'1234 @ local(blah) .machine .example',
447
'first(abc.def)[email protected]',
448
'first(a"bc.def)[email protected]',
449
'first.(")middle.last(")@example.org',
450
'first(abc\(def)@example.org',
451
'first.last@x(1234567890123456789012345678901234567890123456789012345678901234567890).com',
452
'a(a(b(c)d(e(f))g)h(i)j)@example.org',
453
'"hello my name is"@example.com',
454
'"Test \"Fail\" Ing"@example.org',
455
'first.last @example.org',
456
];
457
//Valid explicit IPv6 numeric addresses
458
$validipv6 = [
459
'first.last@[IPv6:::a2:a3:a4:b1:b2:b3:b4]',
460
'first.last@[IPv6:a1:a2:a3:a4:b1:b2:b3::]',
461
'first.last@[IPv6:::]',
462
'first.last@[IPv6:::b4]',
463
'first.last@[IPv6:::b3:b4]',
464
'first.last@[IPv6:a1::b4]',
465
'first.last@[IPv6:a1::]',
466
'first.last@[IPv6:a1:a2::]',
467
'first.last@[IPv6:0123:4567:89ab:cdef::]',
468
'first.last@[IPv6:0123:4567:89ab:CDEF::]',
469
'first.last@[IPv6:::a3:a4:b1:ffff:11.22.33.44]',
470
'first.last@[IPv6:::a2:a3:a4:b1:ffff:11.22.33.44]',
471
'first.last@[IPv6:a1:a2:a3:a4::11.22.33.44]',
472
'first.last@[IPv6:a1:a2:a3:a4:b1::11.22.33.44]',
473
'first.last@[IPv6:a1::11.22.33.44]',
474
'first.last@[IPv6:a1:a2::11.22.33.44]',
475
'first.last@[IPv6:0123:4567:89ab:cdef::11.22.33.44]',
476
'first.last@[IPv6:0123:4567:89ab:CDEF::11.22.33.44]',
477
'first.last@[IPv6:a1::b2:11.22.33.44]',
478
'first.last@[IPv6:::12.34.56.78]',
479
'first.last@[IPv6:1111:2222:3333::4444:12.34.56.78]',
480
'first.last@[IPv6:1111:2222:3333:4444:5555:6666:12.34.56.78]',
481
'first.last@[IPv6:::1111:2222:3333:4444:5555:6666]',
482
'first.last@[IPv6:1111:2222:3333::4444:5555:6666]',
483
'first.last@[IPv6:1111:2222:3333:4444:5555:6666::]',
484
'first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888]',
485
'first.last@[IPv6:1111:2222:3333::4444:5555:12.34.56.78]',
486
'first.last@[IPv6:1111:2222:3333::4444:5555:6666:7777]',
487
];
488
$invalidaddresses = [
489
'[email protected],com',
490
'first\@[email protected]',
491
'123456789012345678901234567890123456789012345678901234567890' .
492
'@12345678901234567890123456789012345678901234 [...]',
493
'first.last',
494
'12345678901234567890123456789012345678901234567890123456789012345@iana.org',
495
'[email protected]',
496
'[email protected]',
497
'[email protected]',
498
'"first"last"@iana.org',
499
'"""@iana.org',
500
'"\"@iana.org',
501
//'""@iana.org',
502
'first\@[email protected]',
503
'first.last@',
504
'x@x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.' .
505
'x23456789.x23456789.x23456789.x23 [...]',
506
'first.last@[.12.34.56.78]',
507
'first.last@[12.34.56.789]',
508
'first.last@[::12.34.56.78]',
509
'first.last@[IPv5:::12.34.56.78]',
510
'first.last@[IPv6:1111:2222:3333:4444:5555:12.34.56.78]',
511
'first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777:12.34.56.78]',
512
'first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777]',
513
'first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888:9999]',
514
'first.last@[IPv6:1111:2222::3333::4444:5555:6666]',
515
'first.last@[IPv6:1111:2222:333x::4444:5555]',
516
'first.last@[IPv6:1111:2222:33333::4444:5555]',
517
'[email protected]',
518
'[email protected]',
519
'first.last@x234567890123456789012345678901234567890123456789012345678901234.iana.org',
520
'abc\@[email protected]',
521
'abc\@iana.org',
522
'Doug\ \"Ace\"\ [email protected]',
523
'abc@[email protected]',
524
'abc\@[email protected]',
525
'abc\@iana.org',
526
'@iana.org',
527
'doug@',
528
'"[email protected]',
529
'ote"@iana.org',
530
'[email protected]',
531
'[email protected]',
532
'[email protected]',
533
'"Doug "Ace" L."@iana.org',
534
'Doug\ \"Ace\"\ L\[email protected]',
535
'hello [email protected]',
536
//'helloworld@iana .org',
537
'[email protected].',
538
'test.iana.org',
539
'[email protected]',
540
'[email protected]',
541
'[email protected]',
542
'test@[email protected]',
543
'test@@iana.org',
544
'-- test [email protected]',
545
'[test]@iana.org',
546
'"test"test"@iana.org',
547
'()[]\;:,><@iana.org',
548
'test@.',
549
'test@example.',
550
'[email protected]',
551
'test@12345678901234567890123456789012345678901234567890123456789012345678901234567890' .
552
'12345678901234567890 [...]',
553
'test@[123.123.123.123',
554
'[email protected]]',
555
'NotAnEmail',
556
'@NotAnEmail',
557
'"test"blah"@iana.org',
558
'[email protected]',
559
'[email protected]',
560
'[email protected]',
561
'[email protected]',
562
'Ima [email protected]',
563
'phil.h\@\@[email protected]',
564
'foo@[\1.2.3.4]',
565
//'first.""[email protected]',
566
'first\[email protected]',
567
'Abc\@[email protected]',
568
'Fred\ [email protected]',
569
'Joe.\[email protected]',
570
'first.last@[IPv6:1111:2222:3333:4444:5555:6666:12.34.567.89]',
571
'{^c\@**Dog^}@cartoon.com',
572
//'"foo"(yay)@(hoopla)[1.2.3.4]',
573
'cal(foo(bar)@iamcal.com',
574
'cal(foo)bar)@iamcal.com',
575
'cal(foo\)@iamcal.com',
576
'first(12345678901234567890123456789012345678901234567890)last@(1234567890123456789' .
577
'01234567890123456789012 [...]',
578
'first(middle)[email protected]',
579
'first(abc("def".ghi).mno)middle(abc("def".ghi).mno).last@(abc("def".ghi).mno)example' .
580
'(abc("def".ghi).mno). [...]',
581
'a(a(b(c)d(e(f))g)(h(i)j)@iana.org',
582
'.@',
583
'@bar.com',
584
'@@bar.com',
585
'aaa.com',
586
'[email protected]',
587
'[email protected]',
588
'aaa@[123.123.123.123]a',
589
'aaa@[123.123.123.333]',
590
'[email protected].',
591
'[email protected]',
592
'[email protected]',
593
'[email protected]',
594
'[email protected]',
595
'[email protected]',
596
'[email protected]',
597
'"Unicode NULL' . chr(0) . '"@char.com',
598
'Unicode NULL' . chr(0) . '@char.com',
599
'first.last@[IPv6::]',
600
'first.last@[IPv6::::]',
601
'first.last@[IPv6::b4]',
602
'first.last@[IPv6::::b4]',
603
'first.last@[IPv6::b3:b4]',
604
'first.last@[IPv6::::b3:b4]',
605
'first.last@[IPv6:a1:::b4]',
606
'first.last@[IPv6:a1:]',
607
'first.last@[IPv6:a1:::]',
608
'first.last@[IPv6:a1:a2:]',
609
'first.last@[IPv6:a1:a2:::]',
610
'first.last@[IPv6::11.22.33.44]',
611
'first.last@[IPv6::::11.22.33.44]',
612
'first.last@[IPv6:a1:11.22.33.44]',
613
'first.last@[IPv6:a1:::11.22.33.44]',
614
'first.last@[IPv6:a1:a2:::11.22.33.44]',
615
'first.last@[IPv6:0123:4567:89ab:cdef::11.22.33.xx]',
616
'first.last@[IPv6:0123:4567:89ab:CDEFF::11.22.33.44]',
617
'first.last@[IPv6:a1::a4:b1::b4:11.22.33.44]',
618
'first.last@[IPv6:a1::11.22.33]',
619
'first.last@[IPv6:a1::11.22.33.44.55]',
620
'first.last@[IPv6:a1::b211.22.33.44]',
621
'first.last@[IPv6:a1::b2::11.22.33.44]',
622
'first.last@[IPv6:a1::b3:]',
623
'first.last@[IPv6::a2::b4]',
624
'first.last@[IPv6:a1:a2:a3:a4:b1:b2:b3:]',
625
'first.last@[IPv6::a2:a3:a4:b1:b2:b3:b4]',
626
'first.last@[IPv6:a1:a2:a3:a4::b1:b2:b3:b4]',
627
//This is a valid RFC5322 address, but we don't want to allow it for obvious reasons!
628
"(\r\n RCPT TO:[email protected]\r\n DATA \\\nSubject: spam10\\\n\r\n Hello," .
629
"\r\n this is a spam mail.\\\n.\r\n QUIT\r\n ) [email protected]",
630
];
631
// IDNs in Unicode and ASCII forms.
632
$unicodeaddresses = [
633
'first.last@bücher.ch',
634
'first.last@кто.рф',
635
'first.last@phplíst.com',
636
];
637
$asciiaddresses = [
638
'[email protected]',
639
'[email protected]',
640
'[email protected]',
641
];
642
$goodfails = [];
643
foreach (array_merge($validaddresses, $asciiaddresses) as $address) {
644
if (!PHPMailer::validateAddress($address)) {
645
$goodfails[] = $address;
646
}
647
}
648
$badpasses = [];
649
foreach (array_merge($invalidaddresses, $unicodeaddresses) as $address) {
650
if (PHPMailer::validateAddress($address)) {
651
$badpasses[] = $address;
652
}
653
}
654
$err = '';
655
if (count($goodfails) > 0) {
656
$err .= "Good addresses that failed validation:\n";
657
$err .= implode("\n", $goodfails);
658
}
659
if (count($badpasses) > 0) {
660
if (!empty($err)) {
661
$err .= "\n\n";
662
}
663
$err .= "Bad addresses that passed validation:\n";
664
$err .= implode("\n", $badpasses);
665
}
666
self::assertEmpty($err, $err);
667
//For coverage
668
self::assertTrue(PHPMailer::validateAddress('[email protected]', 'auto'));
669
self::assertFalse(PHPMailer::validateAddress('[email protected].', 'auto'));
670
self::assertTrue(PHPMailer::validateAddress('[email protected]', 'pcre'));
671
self::assertFalse(PHPMailer::validateAddress('[email protected].', 'pcre'));
672
self::assertTrue(PHPMailer::validateAddress('[email protected]', 'pcre8'));
673
self::assertFalse(PHPMailer::validateAddress('[email protected].', 'pcre8'));
674
self::assertTrue(PHPMailer::validateAddress('[email protected]', 'html5'));
675
self::assertFalse(PHPMailer::validateAddress('[email protected].', 'html5'));
676
self::assertTrue(PHPMailer::validateAddress('[email protected]', 'php'));
677
self::assertFalse(PHPMailer::validateAddress('[email protected].', 'php'));
678
self::assertTrue(PHPMailer::validateAddress('[email protected]', 'noregex'));
679
self::assertFalse(PHPMailer::validateAddress('bad', 'noregex'));
680
}
681
682
/**
683
* Test injecting a custom validator.
684
*/
685
public function testCustomValidator()
686
{
687
//Inject a one-off custom validator
688
self::assertTrue(
689
PHPMailer::validateAddress(
690
'[email protected]',
691
function ($address) {
692
return strpos($address, '@') !== false;
693
}
694
),
695
'Custom validator false negative'
696
);
697
self::assertFalse(
698
PHPMailer::validateAddress(
699
'userexample.com',
700
function ($address) {
701
return strpos($address, '@') !== false;
702
}
703
),
704
'Custom validator false positive'
705
);
706
//Set the default validator to an injected function
707
PHPMailer::$validator = function ($address) {
708
return '[email protected]' === $address;
709
};
710
self::assertTrue(
711
$this->Mail->addAddress('[email protected]'),
712
'Custom default validator false negative'
713
);
714
self::assertFalse(
715
//Need to pick a failing value which would pass all other validators
716
//to be sure we're using our custom one
717
$this->Mail->addAddress('[email protected]'),
718
'Custom default validator false positive'
719
);
720
//Set default validator to PHP built-in
721
PHPMailer::$validator = 'php';
722
self::assertFalse(
723
//This is a valid address that FILTER_VALIDATE_EMAIL thinks is invalid
724
$this->Mail->addAddress('[email protected]'),
725
'PHP validator not behaving as expected'
726
);
727
}
728
729
/**
730
* Word-wrap an ASCII message.
731
*/
732
public function testWordWrap()
733
{
734
$this->Mail->WordWrap = 40;
735
$my_body = str_repeat(
736
'Here is the main body of this message. It should ' .
737
'be quite a few lines. It should be wrapped at ' .
738
'40 characters. Make sure that it is. ',
739
10
740
);
741
$nBodyLen = strlen($my_body);
742
$my_body .= "\n\nThis is the above body length: " . $nBodyLen;
743
744
$this->Mail->Body = $my_body;
745
$this->Mail->Subject .= ': Wordwrap';
746
747
$this->buildBody();
748
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
749
}
750
751
/**
752
* Word-wrap a multibyte message.
753
*/
754
public function testWordWrapMultibyte()
755
{
756
$this->Mail->WordWrap = 40;
757
$my_body = str_repeat(
758
'飛兒樂 團光茫 飛兒樂 團光茫 飛兒樂 團光茫 飛兒樂 團光茫 ' .
759
'飛飛兒樂 團光茫兒樂 團光茫飛兒樂 團光飛兒樂 團光茫飛兒樂 團光茫兒樂 團光茫 ' .
760
'飛兒樂 團光茫飛兒樂 團飛兒樂 團光茫光茫飛兒樂 團光茫. ',
761
10
762
);
763
$nBodyLen = strlen($my_body);
764
$my_body .= "\n\nThis is the above body length: " . $nBodyLen;
765
766
$this->Mail->Body = $my_body;
767
$this->Mail->Subject .= ': Wordwrap multibyte';
768
769
$this->buildBody();
770
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
771
}
772
773
/**
774
* Test low priority.
775
*/
776
public function testLowPriority()
777
{
778
$this->Mail->Priority = 5;
779
$this->Mail->Body = 'Here is the main body. There should be ' .
780
'a reply to address in this message.';
781
$this->Mail->Subject .= ': Low Priority';
782
$this->Mail->addReplyTo('[email protected]', 'Nobody (Unit Test)');
783
784
$this->buildBody();
785
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
786
}
787
788
/**
789
* Simple plain file attachment test.
790
*/
791
public function testMultiplePlainFileAttachment()
792
{
793
$this->Mail->Body = 'Here is the text body';
794
$this->Mail->Subject .= ': Plain + Multiple FileAttachments';
795
796
if (!$this->Mail->addAttachment(realpath($this->INCLUDE_DIR . '/examples/images/phpmailer.png'))) {
797
self::assertTrue(false, $this->Mail->ErrorInfo);
798
799
return;
800
}
801
802
if (!$this->Mail->addAttachment(__FILE__, 'test.txt')) {
803
self::assertTrue(false, $this->Mail->ErrorInfo);
804
805
return;
806
}
807
808
$this->buildBody();
809
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
810
}
811
812
/**
813
* Rejection of non-local file attachments test.
814
*/
815
public function testRejectNonLocalFileAttachment()
816
{
817
self::assertFalse(
818
$this->Mail->addAttachment('https://github.com/PHPMailer/PHPMailer/raw/master/README.md'),
819
'addAttachment should reject remote URLs'
820
);
821
822
self::assertFalse(
823
$this->Mail->addAttachment('phar://phar.php'),
824
'addAttachment should reject phar resources'
825
);
826
}
827
828
/**
829
* Simple plain string attachment test.
830
*/
831
public function testPlainStringAttachment()
832
{
833
$this->Mail->Body = 'Here is the text body';
834
$this->Mail->Subject .= ': Plain + StringAttachment';
835
836
$sAttachment = 'These characters are the content of the ' .
837
"string attachment.\nThis might be taken from a " .
838
'database or some other such thing. ';
839
840
$this->Mail->addStringAttachment($sAttachment, 'string_attach.txt');
841
842
$this->buildBody();
843
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
844
}
845
846
/**
847
* Plain quoted-printable message.
848
*/
849
public function testQuotedPrintable()
850
{
851
$this->Mail->Body = 'Here is the main body';
852
$this->Mail->Subject .= ': Plain + Quoted-printable';
853
$this->Mail->Encoding = 'quoted-printable';
854
855
$this->buildBody();
856
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
857
858
//Check that a quoted printable encode and decode results in the same as went in
859
$t = file_get_contents(__FILE__); //Use this file as test content
860
//Force line breaks to UNIX-style
861
$t = str_replace(["\r\n", "\r"], "\n", $t);
862
self::assertEquals(
863
$t,
864
quoted_printable_decode($this->Mail->encodeQP($t)),
865
'Quoted-Printable encoding round-trip failed'
866
);
867
//Force line breaks to Windows-style
868
$t = str_replace("\n", "\r\n", $t);
869
self::assertEquals(
870
$t,
871
quoted_printable_decode($this->Mail->encodeQP($t)),
872
'Quoted-Printable encoding round-trip failed (Windows line breaks)'
873
);
874
}
875
876
/**
877
* Test header encoding & folding.
878
*/
879
public function testHeaderEncoding()
880
{
881
$this->Mail->CharSet = 'UTF-8';
882
//This should select B-encoding automatically and should fold
883
$bencode = str_repeat('é', PHPMailer::STD_LINE_LENGTH + 1);
884
//This should select Q-encoding automatically and should fold
885
$qencode = str_repeat('e', PHPMailer::STD_LINE_LENGTH) . 'é';
886
//This should select B-encoding automatically and should not fold
887
$bencodenofold = str_repeat('é', 10);
888
//This should select Q-encoding automatically and should not fold
889
$qencodenofold = str_repeat('e', 9) . 'é';
890
//This should Q-encode as ASCII and fold (previously, this did not encode)
891
$longheader = str_repeat('e', PHPMailer::STD_LINE_LENGTH + 10);
892
//This should Q-encode as UTF-8 and fold
893
$longutf8 = str_repeat('é', PHPMailer::STD_LINE_LENGTH + 10);
894
//This should not change
895
$noencode = 'eeeeeeeeee';
896
$this->Mail->isMail();
897
//Expected results
898
899
$bencoderes = '=?UTF-8?B?w6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6k=?=' .
900
PHPMailer::getLE() .
901
' =?UTF-8?B?w6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6k=?=' .
902
PHPMailer::getLE() .
903
' =?UTF-8?B?w6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6k=?=' .
904
PHPMailer::getLE() .
905
' =?UTF-8?B?w6nDqcOpw6nDqcOpw6nDqcOpw6nDqQ==?=';
906
$qencoderes = '=?UTF-8?Q?eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee?=' .
907
PHPMailer::getLE() .
908
' =?UTF-8?Q?eeeeeeeeeeeeeeeeeeeeeeeeee=C3=A9?=';
909
$bencodenofoldres = '=?UTF-8?B?w6nDqcOpw6nDqcOpw6nDqcOpw6k=?=';
910
$qencodenofoldres = '=?UTF-8?Q?eeeeeeeee=C3=A9?=';
911
$longheaderres = '=?us-ascii?Q?eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee?=' .
912
PHPMailer::getLE() . ' =?us-ascii?Q?eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee?=';
913
$longutf8res = '=?UTF-8?B?w6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6k=?=' .
914
PHPMailer::getLE() . ' =?UTF-8?B?w6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6k=?=' .
915
PHPMailer::getLE() . ' =?UTF-8?B?w6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6k=?=' .
916
PHPMailer::getLE() . ' =?UTF-8?B?w6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqcOpw6nDqQ==?=';
917
$noencoderes = 'eeeeeeeeee';
918
self::assertEquals(
919
$bencoderes,
920
$this->Mail->encodeHeader($bencode),
921
'Folded B-encoded header value incorrect'
922
);
923
self::assertEquals(
924
$qencoderes,
925
$this->Mail->encodeHeader($qencode),
926
'Folded Q-encoded header value incorrect'
927
);
928
self::assertEquals(
929
$bencodenofoldres,
930
$this->Mail->encodeHeader($bencodenofold),
931
'B-encoded header value incorrect'
932
);
933
self::assertEquals(
934
$qencodenofoldres,
935
$this->Mail->encodeHeader($qencodenofold),
936
'Q-encoded header value incorrect'
937
);
938
self::assertEquals(
939
$longheaderres,
940
$this->Mail->encodeHeader($longheader),
941
'Long header value incorrect'
942
);
943
self::assertEquals(
944
$longutf8res,
945
$this->Mail->encodeHeader($longutf8),
946
'Long UTF-8 header value incorrect'
947
);
948
self::assertEquals(
949
$noencoderes,
950
$this->Mail->encodeHeader($noencode),
951
'Unencoded header value incorrect'
952
);
953
}
954
955
/**
956
* Send an HTML message.
957
*/
958
public function testHtml()
959
{
960
$this->Mail->isHTML(true);
961
$this->Mail->Subject .= ': HTML only';
962
963
$this->Mail->Body = <<<'EOT'
964
<!DOCTYPE html>
965
<html lang="en">
966
<head>
967
<title>HTML email test</title>
968
</head>
969
<body>
970
<h1>PHPMailer does HTML!</h1>
971
<p>This is a <strong>test message</strong> written in HTML.<br>
972
Go to <a href="https://github.com/PHPMailer/PHPMailer/">https://github.com/PHPMailer/PHPMailer/</a>
973
for new versions of PHPMailer.</p>
974
<p>Thank you!</p>
975
</body>
976
</html>
977
EOT;
978
$this->buildBody();
979
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
980
$msg = $this->Mail->getSentMIMEMessage();
981
self::assertNotContains("\r\n\r\nMIME-Version:", $msg, 'Incorrect MIME headers');
982
}
983
984
/**
985
* Send an HTML message specifying the DSN notifications we expect.
986
*/
987
public function testDsn()
988
{
989
$this->Mail->isHTML(true);
990
$this->Mail->Subject .= ': HTML only';
991
992
$this->Mail->Body = <<<'EOT'
993
<!DOCTYPE html>
994
<html lang="en">
995
<head>
996
<title>HTML email test</title>
997
</head>
998
<body>
999
<p>PHPMailer</p>
1000
</body>
1001
</html>
1002
EOT;
1003
$this->buildBody();
1004
$this->Mail->dsn = 'SUCCESS,FAILURE';
1005
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1006
//Sends the same mail, but sets the DSN notification to NEVER
1007
$this->Mail->dsn = 'NEVER';
1008
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1009
}
1010
1011
/**
1012
* createBody test of switch case
1013
*/
1014
public function testCreateBody()
1015
{
1016
$PHPMailer = new PHPMailer();
1017
$reflection = new \ReflectionClass($PHPMailer);
1018
$property = $reflection->getProperty('message_type');
1019
$property->setAccessible(true);
1020
$property->setValue($PHPMailer, 'inline');
1021
self::assertInternalType('string', $PHPMailer->createBody());
1022
1023
$property->setValue($PHPMailer, 'attach');
1024
self::assertInternalType('string', $PHPMailer->createBody());
1025
1026
$property->setValue($PHPMailer, 'inline_attach');
1027
self::assertInternalType('string', $PHPMailer->createBody());
1028
1029
$property->setValue($PHPMailer, 'alt');
1030
self::assertInternalType('string', $PHPMailer->createBody());
1031
1032
$property->setValue($PHPMailer, 'alt_inline');
1033
self::assertInternalType('string', $PHPMailer->createBody());
1034
1035
$property->setValue($PHPMailer, 'alt_attach');
1036
self::assertInternalType('string', $PHPMailer->createBody());
1037
1038
$property->setValue($PHPMailer, 'alt_inline_attach');
1039
self::assertInternalType('string', $PHPMailer->createBody());
1040
}
1041
1042
/**
1043
* Send a message containing ISO-8859-1 text.
1044
*/
1045
public function testHtmlIso8859()
1046
{
1047
$this->Mail->isHTML(true);
1048
$this->Mail->Subject .= ': ISO-8859-1 HTML';
1049
$this->Mail->CharSet = PHPMailer::CHARSET_ISO88591;
1050
1051
//This file is in ISO-8859-1 charset
1052
//Needs to be external because this file is in UTF-8
1053
$content = file_get_contents(realpath($this->INCLUDE_DIR . '/examples/contents.html'));
1054
// This is the string 'éèîüçÅñæß' in ISO-8859-1, base-64 encoded
1055
$check = base64_decode('6eju/OfF8ebf');
1056
//Make sure it really is in ISO-8859-1!
1057
$this->Mail->msgHTML(
1058
mb_convert_encoding(
1059
$content,
1060
'ISO-8859-1',
1061
mb_detect_encoding($content, 'UTF-8, ISO-8859-1, ISO-8859-15', true)
1062
),
1063
realpath($this->INCLUDE_DIR . '/examples')
1064
);
1065
$this->buildBody();
1066
self::assertContains($check, $this->Mail->Body, 'ISO message body does not contain expected text');
1067
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1068
}
1069
1070
/**
1071
* Send a message containing multilingual UTF-8 text.
1072
*/
1073
public function testHtmlUtf8()
1074
{
1075
$this->Mail->isHTML(true);
1076
$this->Mail->Subject .= ': UTF-8 HTML Пустое тело сообщения';
1077
$this->Mail->CharSet = 'UTF-8';
1078
1079
$this->Mail->Body = <<<'EOT'
1080
<!DOCTYPE html>
1081
<html lang="en">
1082
<head>
1083
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
1084
<title>HTML email test</title>
1085
</head>
1086
<body>
1087
<p>Chinese text: 郵件內容為空</p>
1088
<p>Russian text: Пустое тело сообщения</p>
1089
<p>Armenian text: Հաղորդագրությունը դատարկ է</p>
1090
<p>Czech text: Prázdné tělo zprávy</p>
1091
</body>
1092
</html>
1093
EOT;
1094
$this->buildBody();
1095
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1096
$msg = $this->Mail->getSentMIMEMessage();
1097
self::assertNotContains("\r\n\r\nMIME-Version:", $msg, 'Incorrect MIME headers');
1098
}
1099
1100
/**
1101
* Send a message containing multilingual UTF-8 text with an embedded image.
1102
*/
1103
public function testUtf8WithEmbeddedImage()
1104
{
1105
$this->Mail->isHTML(true);
1106
$this->Mail->Subject .= ': UTF-8 with embedded image';
1107
$this->Mail->CharSet = 'UTF-8';
1108
1109
$this->Mail->Body = <<<'EOT'
1110
<!DOCTYPE html>
1111
<html lang="en">
1112
<head>
1113
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
1114
<title>HTML email test</title>
1115
</head>
1116
<body>
1117
<p>Chinese text: 郵件內容為空</p>
1118
<p>Russian text: Пустое тело сообщения</p>
1119
<p>Armenian text: Հաղորդագրությունը դատարկ է</p>
1120
<p>Czech text: Prázdné tělo zprávy</p>
1121
Embedded Image: <img alt="phpmailer" src="cid:bäck">
1122
</body>
1123
</html>
1124
EOT;
1125
$this->Mail->addEmbeddedImage(
1126
realpath($this->INCLUDE_DIR . '/examples/images/phpmailer.png'),
1127
'bäck',
1128
'phpmailer.png',
1129
'base64',
1130
'image/png'
1131
);
1132
$this->buildBody();
1133
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1134
}
1135
1136
/**
1137
* Send a message containing multilingual UTF-8 text.
1138
*/
1139
public function testPlainUtf8()
1140
{
1141
$this->Mail->isHTML(false);
1142
$this->Mail->Subject .= ': UTF-8 plain text';
1143
$this->Mail->CharSet = 'UTF-8';
1144
1145
$this->Mail->Body = <<<'EOT'
1146
Chinese text: 郵件內容為空
1147
Russian text: Пустое тело сообщения
1148
Armenian text: Հաղորդագրությունը դատարկ է
1149
Czech text: Prázdné tělo zprávy
1150
EOT;
1151
$this->buildBody();
1152
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1153
$msg = $this->Mail->getSentMIMEMessage();
1154
self::assertNotContains("\r\n\r\nMIME-Version:", $msg, 'Incorrect MIME headers');
1155
}
1156
1157
/**
1158
* Test simple message builder and html2text converters.
1159
*/
1160
public function testMsgHTML()
1161
{
1162
$message = file_get_contents(realpath($this->INCLUDE_DIR . '/examples/contentsutf8.html'));
1163
$this->Mail->CharSet = PHPMailer::CHARSET_UTF8;
1164
$this->Mail->Body = '';
1165
$this->Mail->AltBody = '';
1166
//Uses internal HTML to text conversion
1167
$this->Mail->msgHTML($message, realpath($this->INCLUDE_DIR . '/examples'));
1168
$sub = $this->Mail->Subject . ': msgHTML';
1169
$this->Mail->Subject .= $sub;
1170
1171
self::assertNotEmpty($this->Mail->Body, 'Body not set by msgHTML');
1172
self::assertNotEmpty($this->Mail->AltBody, 'AltBody not set by msgHTML');
1173
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1174
1175
//Again, using a custom HTML to text converter
1176
$this->Mail->AltBody = '';
1177
$this->Mail->msgHTML(
1178
$message,
1179
realpath($this->INCLUDE_DIR . '/examples'),
1180
function ($html) {
1181
return strtoupper(strip_tags($html));
1182
}
1183
);
1184
$this->Mail->Subject = $sub . ' + custom html2text';
1185
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1186
1187
//Test that local paths without a basedir are ignored
1188
$this->Mail->msgHTML('<img src="/etc/hostname">test');
1189
self::assertContains('src="/etc/hostname"', $this->Mail->Body);
1190
//Test that local paths with a basedir are not ignored
1191
$this->Mail->msgHTML('<img src="composer.json">test', realpath($this->INCLUDE_DIR));
1192
self::assertNotContains('src="composer.json"', $this->Mail->Body);
1193
//Test that local paths with parent traversal are ignored
1194
$this->Mail->msgHTML('<img src="../composer.json">test', realpath($this->INCLUDE_DIR));
1195
self::assertNotContains('src="composer.json"', $this->Mail->Body);
1196
//Test that existing embedded URLs are ignored
1197
$this->Mail->msgHTML('<img src="cid:5d41402abc4b2a76b9719d911017c592">test');
1198
self::assertContains('src="cid:5d41402abc4b2a76b9719d911017c592"', $this->Mail->Body);
1199
//Test that absolute URLs are ignored
1200
$this->Mail->msgHTML('<img src="https://github.com/PHPMailer/PHPMailer/blob/master/composer.json">test');
1201
self::assertContains(
1202
'src="https://github.com/PHPMailer/PHPMailer/blob/master/composer.json"',
1203
$this->Mail->Body
1204
);
1205
//Test that absolute URLs with anonymous/relative protocol are ignored
1206
//Note that such URLs will not work in email anyway because they have no protocol to be relative to
1207
$this->Mail->msgHTML('<img src="//github.com/PHPMailer/PHPMailer/blob/master/composer.json">test');
1208
self::assertContains('src="//github.com/PHPMailer/PHPMailer/blob/master/composer.json"', $this->Mail->Body);
1209
}
1210
1211
/**
1212
* Simple HTML and attachment test.
1213
*/
1214
public function testHTMLAttachment()
1215
{
1216
$this->Mail->Body = 'This is the <strong>HTML</strong> part of the email.';
1217
$this->Mail->Subject .= ': HTML + Attachment';
1218
$this->Mail->isHTML(true);
1219
$this->Mail->CharSet = 'UTF-8';
1220
1221
if (!$this->Mail->addAttachment(
1222
realpath($this->INCLUDE_DIR . '/examples/images/phpmailer_mini.png'),
1223
'phpmailer_mini.png'
1224
)
1225
) {
1226
self::assertTrue(false, $this->Mail->ErrorInfo);
1227
1228
return;
1229
}
1230
1231
//Make sure that trying to attach a nonexistent file fails
1232
$filename = __FILE__ . md5(microtime()) . 'nonexistent_file.txt';
1233
self::assertFalse($this->Mail->addAttachment($filename));
1234
//Make sure that trying to attach an existing but unreadable file fails
1235
touch($filename);
1236
chmod($filename, 0200);
1237
self::assertFalse($this->Mail->addAttachment($filename));
1238
chmod($filename, 0644);
1239
unlink($filename);
1240
1241
$this->buildBody();
1242
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1243
}
1244
1245
/**
1246
* Attachment naming test.
1247
*/
1248
public function testAttachmentNaming()
1249
{
1250
$this->Mail->Body = 'Attachments.';
1251
$this->Mail->Subject .= ': Attachments';
1252
$this->Mail->isHTML(true);
1253
$this->Mail->CharSet = 'UTF-8';
1254
$this->Mail->addAttachment(
1255
realpath($this->INCLUDE_DIR . '/examples/images/phpmailer_mini.png'),
1256
'phpmailer_mini.png";.jpg'
1257
);
1258
$this->Mail->addAttachment(
1259
realpath($this->INCLUDE_DIR . '/examples/images/phpmailer.png'),
1260
'phpmailer.png'
1261
);
1262
$this->Mail->addAttachment(
1263
realpath($this->INCLUDE_DIR . '/examples/images/PHPMailer card logo.png'),
1264
'PHPMailer card logo.png'
1265
);
1266
$this->Mail->addAttachment(
1267
realpath($this->INCLUDE_DIR . '/examples/images/phpmailer_mini.png'),
1268
'phpmailer_mini.png\\\";.jpg'
1269
);
1270
$this->buildBody();
1271
$this->Mail->preSend();
1272
$message = $this->Mail->getSentMIMEMessage();
1273
self::assertContains(
1274
'Content-Type: image/png; name="phpmailer_mini.png\";.jpg"',
1275
$message,
1276
'Name containing double quote should be escaped in Content-Type'
1277
);
1278
self::assertContains(
1279
'Content-Disposition: attachment; filename="phpmailer_mini.png\";.jpg"',
1280
$message,
1281
'Filename containing double quote should be escaped in Content-Disposition'
1282
);
1283
self::assertContains(
1284
'Content-Type: image/png; name=phpmailer.png',
1285
$message,
1286
'Name without special chars should not be quoted in Content-Type'
1287
);
1288
self::assertContains(
1289
'Content-Disposition: attachment; filename=phpmailer.png',
1290
$message,
1291
'Filename without special chars should not be quoted in Content-Disposition'
1292
);
1293
self::assertContains(
1294
'Content-Type: image/png; name="PHPMailer card logo.png"',
1295
$message,
1296
'Name with spaces should be quoted in Content-Type'
1297
);
1298
self::assertContains(
1299
'Content-Disposition: attachment; filename="PHPMailer card logo.png"',
1300
$message,
1301
'Filename with spaces should be quoted in Content-Disposition'
1302
);
1303
}
1304
1305
/**
1306
* Test embedded image without a name.
1307
*/
1308
public function testHTMLStringEmbedNoName()
1309
{
1310
$this->Mail->Body = 'This is the <strong>HTML</strong> part of the email.';
1311
$this->Mail->Subject .= ': HTML + unnamed embedded image';
1312
$this->Mail->isHTML(true);
1313
1314
if (!$this->Mail->addStringEmbeddedImage(
1315
file_get_contents(realpath($this->INCLUDE_DIR . '/examples/images/phpmailer_mini.png')),
1316
hash('sha256', 'phpmailer_mini.png') . '@phpmailer.0',
1317
'', //Intentionally empty name
1318
'base64',
1319
'', //Intentionally empty MIME type
1320
'inline'
1321
)) {
1322
self::assertTrue(false, $this->Mail->ErrorInfo);
1323
1324
return;
1325
}
1326
1327
$this->buildBody();
1328
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1329
}
1330
1331
/**
1332
* Simple HTML and multiple attachment test.
1333
*/
1334
public function testHTMLMultiAttachment()
1335
{
1336
$this->Mail->Body = 'This is the <strong>HTML</strong> part of the email.';
1337
$this->Mail->Subject .= ': HTML + multiple Attachment';
1338
$this->Mail->isHTML(true);
1339
1340
if (!$this->Mail->addAttachment(
1341
realpath($this->INCLUDE_DIR . '/examples/images/phpmailer_mini.png'),
1342
'phpmailer_mini.png'
1343
)
1344
) {
1345
self::assertTrue(false, $this->Mail->ErrorInfo);
1346
1347
return;
1348
}
1349
1350
if (!$this->Mail->addAttachment(
1351
realpath($this->INCLUDE_DIR . '/examples/images/phpmailer.png'),
1352
'phpmailer.png'
1353
)
1354
) {
1355
self::assertTrue(false, $this->Mail->ErrorInfo);
1356
1357
return;
1358
}
1359
1360
$this->buildBody();
1361
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1362
}
1363
1364
/**
1365
* An embedded attachment test.
1366
*/
1367
public function testEmbeddedImage()
1368
{
1369
$this->Mail->Body = 'Embedded Image: <img alt="phpmailer" src="' .
1370
'cid:my-attach">' .
1371
'Here is an image!';
1372
$this->Mail->Subject .= ': Embedded Image';
1373
$this->Mail->isHTML(true);
1374
1375
if (!$this->Mail->addEmbeddedImage(
1376
realpath($this->INCLUDE_DIR . '/examples/images/phpmailer.png'),
1377
'my-attach',
1378
'phpmailer.png',
1379
'base64',
1380
'image/png'
1381
)
1382
) {
1383
self::assertTrue(false, $this->Mail->ErrorInfo);
1384
1385
return;
1386
}
1387
1388
$this->buildBody();
1389
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1390
$this->Mail->clearAttachments();
1391
$this->Mail->msgHTML('<!DOCTYPE html>
1392
<html lang="en">
1393
<head>
1394
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1395
<title>E-Mail Inline Image Test</title>
1396
</head>
1397
<body>
1398
<p><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p>
1399
</body>
1400
</html>');
1401
$this->Mail->preSend();
1402
self::assertContains(
1403
'Content-ID: <[email protected]>',
1404
$this->Mail->getSentMIMEMessage(),
1405
'Embedded image header encoding incorrect.'
1406
);
1407
//For code coverage
1408
$this->Mail->addEmbeddedImage('thisfiledoesntexist', 'xyz'); //Non-existent file
1409
$this->Mail->addEmbeddedImage(__FILE__, '123'); //Missing name
1410
}
1411
1412
/**
1413
* An embedded attachment test.
1414
*/
1415
public function testMultiEmbeddedImage()
1416
{
1417
$this->Mail->Body = 'Embedded Image: <img alt="phpmailer" src="' .
1418
'cid:my-attach">' .
1419
'Here is an image!</a>';
1420
$this->Mail->Subject .= ': Embedded Image + Attachment';
1421
$this->Mail->isHTML(true);
1422
1423
if (!$this->Mail->addEmbeddedImage(
1424
realpath($this->INCLUDE_DIR . '/examples/images/phpmailer.png'),
1425
'my-attach',
1426
'phpmailer.png',
1427
'base64',
1428
'image/png'
1429
)
1430
) {
1431
self::assertTrue(false, $this->Mail->ErrorInfo);
1432
1433
return;
1434
}
1435
1436
if (!$this->Mail->addAttachment(__FILE__, 'test.txt')) {
1437
self::assertTrue(false, $this->Mail->ErrorInfo);
1438
1439
return;
1440
}
1441
1442
$this->buildBody();
1443
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1444
}
1445
1446
/**
1447
* Simple multipart/alternative test.
1448
*/
1449
public function testAltBody()
1450
{
1451
$this->Mail->Body = 'This is the <strong>HTML</strong> part of the email.';
1452
$this->Mail->AltBody = 'Here is the plain text body of this message. ' .
1453
'It should be quite a few lines. It should be wrapped at ' .
1454
'40 characters. Make sure that it is.';
1455
$this->Mail->WordWrap = 40;
1456
$this->addNote('This is a multipart/alternative email');
1457
$this->Mail->Subject .= ': AltBody + Word Wrap';
1458
1459
$this->buildBody();
1460
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1461
}
1462
1463
/**
1464
* Simple HTML and attachment test.
1465
*/
1466
public function testAltBodyAttachment()
1467
{
1468
$this->Mail->Body = 'This is the <strong>HTML</strong> part of the email.';
1469
$this->Mail->AltBody = 'This is the text part of the email.';
1470
$this->Mail->Subject .= ': AltBody + Attachment';
1471
$this->Mail->isHTML(true);
1472
1473
if (!$this->Mail->addAttachment(__FILE__, 'test_attach.txt')) {
1474
self::assertTrue(false, $this->Mail->ErrorInfo);
1475
1476
return;
1477
}
1478
1479
//Test using non-existent UNC path
1480
self::assertFalse($this->Mail->addAttachment('\\\\nowhere\nothing'));
1481
1482
$this->buildBody();
1483
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1484
}
1485
1486
/**
1487
* Test sending multiple messages with separate connections.
1488
*/
1489
public function testMultipleSend()
1490
{
1491
$this->Mail->Body = 'Sending two messages without keepalive';
1492
$this->buildBody();
1493
$subject = $this->Mail->Subject;
1494
1495
$this->Mail->Subject = $subject . ': SMTP 1';
1496
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1497
1498
$this->Mail->Subject = $subject . ': SMTP 2';
1499
$this->Mail->Sender = '[email protected]';
1500
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1501
}
1502
1503
/**
1504
* Test sending using SendMail.
1505
*/
1506
public function testSendmailSend()
1507
{
1508
$this->Mail->Body = 'Sending via sendmail';
1509
$this->buildBody();
1510
$subject = $this->Mail->Subject;
1511
1512
$this->Mail->Subject = $subject . ': sendmail';
1513
$this->Mail->isSendmail();
1514
1515
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1516
}
1517
1518
/**
1519
* Test sending using Qmail.
1520
*/
1521
public function testQmailSend()
1522
{
1523
//Only run if we have qmail installed
1524
if (file_exists('/var/qmail/bin/qmail-inject')) {
1525
$this->Mail->Body = 'Sending via qmail';
1526
$this->buildBody();
1527
$subject = $this->Mail->Subject;
1528
1529
$this->Mail->Subject = $subject . ': qmail';
1530
$this->Mail->isQmail();
1531
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1532
} else {
1533
self::markTestSkipped('Qmail is not installed');
1534
}
1535
}
1536
1537
/**
1538
* Test sending using PHP mail() function.
1539
*/
1540
public function testMailSend()
1541
{
1542
$sendmail = ini_get('sendmail_path');
1543
//No path in sendmail_path
1544
if (strpos($sendmail, '/') === false) {
1545
ini_set('sendmail_path', '/usr/sbin/sendmail -t -i ');
1546
}
1547
$this->Mail->Body = 'Sending via mail()';
1548
$this->buildBody();
1549
$this->Mail->Subject = $this->Mail->Subject . ': mail()';
1550
$this->Mail->clearAddresses();
1551
$this->Mail->clearCCs();
1552
$this->Mail->clearBCCs();
1553
$this->setAddress('[email protected]', 'totest');
1554
$this->setAddress('[email protected]', 'cctest', $sType = 'cc');
1555
$this->setAddress('[email protected]', 'bcctest', $sType = 'bcc');
1556
$this->Mail->addReplyTo('[email protected]', 'replytotest');
1557
self::assertContains('[email protected]', $this->Mail->getToAddresses()[0]);
1558
self::assertContains('[email protected]', $this->Mail->getCcAddresses()[0]);
1559
self::assertContains('[email protected]', $this->Mail->getBccAddresses()[0]);
1560
self::assertContains(
1561
'[email protected]',
1562
$this->Mail->getReplyToAddresses()['[email protected]']
1563
);
1564
self::assertTrue($this->Mail->getAllRecipientAddresses()['[email protected]']);
1565
self::assertTrue($this->Mail->getAllRecipientAddresses()['[email protected]']);
1566
self::assertTrue($this->Mail->getAllRecipientAddresses()['[email protected]']);
1567
1568
$this->Mail->createHeader();
1569
$this->Mail->isMail();
1570
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1571
$msg = $this->Mail->getSentMIMEMessage();
1572
self::assertNotContains("\r\n\r\nMIME-Version:", $msg, 'Incorrect MIME headers');
1573
}
1574
1575
/**
1576
* Test sending an empty body.
1577
*/
1578
public function testEmptyBody()
1579
{
1580
$this->buildBody();
1581
$this->Mail->Body = '';
1582
$this->Mail->Subject = $this->Mail->Subject . ': Empty Body';
1583
$this->Mail->isMail();
1584
$this->Mail->AllowEmpty = true;
1585
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1586
$this->Mail->AllowEmpty = false;
1587
self::assertFalse($this->Mail->send(), $this->Mail->ErrorInfo);
1588
}
1589
1590
/**
1591
* Test constructing a multipart message that contains lines that are too long for RFC compliance.
1592
*/
1593
public function testLongBody()
1594
{
1595
$oklen = str_repeat(str_repeat('0', PHPMailer::MAX_LINE_LENGTH) . PHPMailer::getLE(), 2);
1596
//Use +2 to ensure line length is over limit - LE may only be 1 char
1597
$badlen = str_repeat(str_repeat('1', PHPMailer::MAX_LINE_LENGTH + 2) . PHPMailer::getLE(), 2);
1598
1599
$this->Mail->Body = 'This message contains lines that are too long.' .
1600
PHPMailer::getLE() . $oklen . $badlen . $oklen;
1601
self::assertTrue(
1602
PHPMailer::hasLineLongerThanMax($this->Mail->Body),
1603
'Test content does not contain long lines!'
1604
);
1605
$this->Mail->isHTML();
1606
$this->buildBody();
1607
$this->Mail->AltBody = $this->Mail->Body;
1608
$this->Mail->Encoding = '8bit';
1609
$this->Mail->preSend();
1610
$message = $this->Mail->getSentMIMEMessage();
1611
self::assertFalse(
1612
PHPMailer::hasLineLongerThanMax($message),
1613
'Long line not corrected (Max: ' . (PHPMailer::MAX_LINE_LENGTH + strlen(PHPMailer::getLE())) . ' chars)'
1614
);
1615
self::assertContains(
1616
'Content-Transfer-Encoding: quoted-printable',
1617
$message,
1618
'Long line did not cause transfer encoding switch.'
1619
);
1620
}
1621
1622
/**
1623
* Test constructing a message that does NOT contain lines that are too long for RFC compliance.
1624
*/
1625
public function testShortBody()
1626
{
1627
$oklen = str_repeat(str_repeat('0', PHPMailer::MAX_LINE_LENGTH) . PHPMailer::getLE(), 10);
1628
1629
$this->Mail->Body = 'This message does not contain lines that are too long.' .
1630
PHPMailer::getLE() . $oklen;
1631
self::assertFalse(
1632
PHPMailer::hasLineLongerThanMax($this->Mail->Body),
1633
'Test content contains long lines!'
1634
);
1635
$this->buildBody();
1636
$this->Mail->Encoding = '8bit';
1637
$this->Mail->preSend();
1638
$message = $this->Mail->getSentMIMEMessage();
1639
self::assertFalse(PHPMailer::hasLineLongerThanMax($message), 'Long line not corrected.');
1640
self::assertNotContains(
1641
'Content-Transfer-Encoding: quoted-printable',
1642
$message,
1643
'Short line caused transfer encoding switch.'
1644
);
1645
}
1646
1647
/**
1648
* Test keepalive (sending multiple messages in a single connection).
1649
*/
1650
public function testSmtpKeepAlive()
1651
{
1652
$this->Mail->Body = 'SMTP keep-alive test.';
1653
$this->buildBody();
1654
$subject = $this->Mail->Subject;
1655
1656
$this->Mail->SMTPKeepAlive = true;
1657
$this->Mail->Subject = $subject . ': SMTP keep-alive 1';
1658
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1659
1660
$this->Mail->Subject = $subject . ': SMTP keep-alive 2';
1661
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1662
$this->Mail->smtpClose();
1663
}
1664
1665
/**
1666
* Test this denial of service attack.
1667
*
1668
* @see http://www.cybsec.com/vuln/PHPMailer-DOS.pdf
1669
*/
1670
public function testDenialOfServiceAttack()
1671
{
1672
$this->Mail->Body = 'This should no longer cause a denial of service.';
1673
$this->buildBody();
1674
1675
$this->Mail->Subject = substr(str_repeat('0123456789', 100), 0, 998);
1676
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
1677
}
1678
1679
/**
1680
* Tests this denial of service attack.
1681
*
1682
* @see https://sourceforge.net/p/phpmailer/bugs/383/
1683
* According to the ticket, this should get stuck in a loop, though I can't make it happen.
1684
*/
1685
public function testDenialOfServiceAttack2()
1686
{
1687
//Encoding name longer than 68 chars
1688
$this->Mail->Encoding = '1234567890123456789012345678901234567890123456789012345678901234567890';
1689
//Call wrapText with a zero length value
1690
$this->Mail->wrapText(str_repeat('This should no longer cause a denial of service. ', 30), 0);
1691
}
1692
1693
/**
1694
* Test error handling.
1695
*/
1696
public function testError()
1697
{
1698
$this->Mail->Subject .= ': Error handling test - this should be sent ok';
1699
$this->buildBody();
1700
$this->Mail->clearAllRecipients(); // no addresses should cause an error
1701
self::assertTrue($this->Mail->isError() == false, 'Error found');
1702
self::assertTrue($this->Mail->send() == false, 'send succeeded');
1703
self::assertTrue($this->Mail->isError(), 'No error found');
1704
self::assertEquals('You must provide at least one recipient email address.', $this->Mail->ErrorInfo);
1705
$this->Mail->addAddress($_REQUEST['mail_to']);
1706
self::assertTrue($this->Mail->send(), 'send failed');
1707
}
1708
1709
/**
1710
* Test addressing.
1711
*/
1712
public function testAddressing()
1713
{
1714
self::assertFalse($this->Mail->addAddress(''), 'Empty address accepted');
1715
self::assertFalse($this->Mail->addAddress('', 'Nobody'), 'Empty address with name accepted');
1716
self::assertFalse($this->Mail->addAddress('[email protected]'), 'Invalid address accepted');
1717
self::assertTrue($this->Mail->addAddress('[email protected]'), 'Addressing failed');
1718
self::assertFalse($this->Mail->addAddress('[email protected]'), 'Duplicate addressing failed');
1719
self::assertTrue($this->Mail->addCC('[email protected]'), 'CC addressing failed');
1720
self::assertFalse($this->Mail->addCC('[email protected]'), 'CC duplicate addressing failed');
1721
self::assertFalse($this->Mail->addCC('[email protected]'), 'CC duplicate addressing failed (2)');
1722
self::assertTrue($this->Mail->addBCC('[email protected]'), 'BCC addressing failed');
1723
self::assertFalse($this->Mail->addBCC('[email protected]'), 'BCC duplicate addressing failed');
1724
self::assertFalse($this->Mail->addBCC('[email protected]'), 'BCC duplicate addressing failed (2)');
1725
self::assertTrue($this->Mail->addReplyTo('[email protected]'), 'Replyto Addressing failed');
1726
self::assertFalse($this->Mail->addReplyTo('[email protected]'), 'Invalid Replyto address accepted');
1727
self::assertTrue($this->Mail->setFrom('[email protected]', 'some name'), 'setFrom failed');
1728
self::assertFalse($this->Mail->setFrom('[email protected].', 'some name'), 'setFrom accepted invalid address');
1729
$this->Mail->Sender = '';
1730
$this->Mail->setFrom('[email protected]', 'some name', true);
1731
self::assertEquals($this->Mail->Sender, '[email protected]', 'setFrom failed to set sender');
1732
$this->Mail->Sender = '';
1733
$this->Mail->setFrom('[email protected]', 'some name', false);
1734
self::assertEquals($this->Mail->Sender, '', 'setFrom should not have set sender');
1735
$this->Mail->clearCCs();
1736
$this->Mail->clearBCCs();
1737
$this->Mail->clearReplyTos();
1738
}
1739
1740
/**
1741
* Test addressing.
1742
*/
1743
public function testAddressing2()
1744
{
1745
$this->buildBody();
1746
$this->Mail->setFrom('[email protected]', '"Bob\'s Burgers" (Bob\'s "Burgers")', true);
1747
$this->Mail->isSMTP();
1748
$this->Mail->Subject .= ': quotes in from name';
1749
self::assertTrue($this->Mail->send(), 'send failed');
1750
}
1751
1752
/**
1753
* Test RFC822 address splitting.
1754
*/
1755
public function testAddressSplitting()
1756
{
1757
//Test built-in address parser
1758
self::assertCount(
1759
2,
1760
PHPMailer::parseAddresses(
1761
'Joe User <[email protected]>, Jill User <[email protected]>'
1762
),
1763
'Failed to recognise address list (IMAP parser)'
1764
);
1765
self::assertEquals(
1766
[
1767
['name' => 'Joe User', 'address' => '[email protected]'],
1768
['name' => 'Jill User', 'address' => '[email protected]'],
1769
['name' => '', 'address' => '[email protected]'],
1770
],
1771
PHPMailer::parseAddresses(
1772
'Joe User <[email protected]>,'
1773
. 'Jill User <[email protected]>,'
1774
. '[email protected],'
1775
),
1776
'Parsed addresses'
1777
);
1778
//Test simple address parser
1779
self::assertCount(
1780
2,
1781
PHPMailer::parseAddresses(
1782
'Joe User <[email protected]>, Jill User <[email protected]>',
1783
false
1784
),
1785
'Failed to recognise address list'
1786
);
1787
//Test single address
1788
self::assertNotEmpty(
1789
PHPMailer::parseAddresses(
1790
'Joe User <[email protected]>',
1791
false
1792
),
1793
'Failed to recognise single address'
1794
);
1795
//Test quoted name IMAP
1796
self::assertNotEmpty(
1797
PHPMailer::parseAddresses(
1798
'Tim "The Book" O\'Reilly <[email protected]>'
1799
),
1800
'Failed to recognise quoted name (IMAP)'
1801
);
1802
//Test quoted name
1803
self::assertNotEmpty(
1804
PHPMailer::parseAddresses(
1805
'Tim "The Book" O\'Reilly <[email protected]>',
1806
false
1807
),
1808
'Failed to recognise quoted name'
1809
);
1810
//Test single address IMAP
1811
self::assertNotEmpty(
1812
PHPMailer::parseAddresses(
1813
'Joe User <[email protected]>'
1814
),
1815
'Failed to recognise single address (IMAP)'
1816
);
1817
//Test unnamed address
1818
self::assertNotEmpty(
1819
PHPMailer::parseAddresses(
1820
'[email protected]',
1821
false
1822
),
1823
'Failed to recognise unnamed address'
1824
);
1825
//Test unnamed address IMAP
1826
self::assertNotEmpty(
1827
PHPMailer::parseAddresses(
1828
'[email protected]'
1829
),
1830
'Failed to recognise unnamed address (IMAP)'
1831
);
1832
//Test invalid addresses
1833
self::assertEmpty(
1834
PHPMailer::parseAddresses(
1835
'Joe User <[email protected].>, Jill User <[email protected]>'
1836
),
1837
'Failed to recognise invalid addresses (IMAP)'
1838
);
1839
//Test invalid addresses
1840
self::assertEmpty(
1841
PHPMailer::parseAddresses(
1842
'Joe User <[email protected].>, Jill User <[email protected]>',
1843
false
1844
),
1845
'Failed to recognise invalid addresses'
1846
);
1847
}
1848
1849
/**
1850
* Test address escaping.
1851
*/
1852
public function testAddressEscaping()
1853
{
1854
$this->Mail->Subject .= ': Address escaping';
1855
$this->Mail->clearAddresses();
1856
$this->Mail->addAddress('[email protected]', 'Tim "The Book" O\'Reilly');
1857
$this->Mail->Body = 'Test correct escaping of quotes in addresses.';
1858
$this->buildBody();
1859
$this->Mail->preSend();
1860
$b = $this->Mail->getSentMIMEMessage();
1861
self::assertContains('To: "Tim \"The Book\" O\'Reilly" <[email protected]>', $b);
1862
1863
$this->Mail->Subject .= ': Address escaping invalid';
1864
$this->Mail->clearAddresses();
1865
$this->Mail->addAddress('[email protected]', 'Tim "The Book" O\'Reilly');
1866
$this->Mail->addAddress('invalidaddressexample.com', 'invalidaddress');
1867
$this->Mail->Body = 'invalid address';
1868
$this->buildBody();
1869
$this->Mail->preSend();
1870
self::assertEquals('Invalid address: (to): invalidaddressexample.com', $this->Mail->ErrorInfo);
1871
1872
$this->Mail->addAttachment(
1873
realpath($this->INCLUDE_DIR . '/examples/images/phpmailer_mini.png'),
1874
'phpmailer_mini.png'
1875
);
1876
self::assertTrue($this->Mail->attachmentExists());
1877
}
1878
1879
/**
1880
* Test MIME structure assembly.
1881
*/
1882
public function testMIMEStructure()
1883
{
1884
$this->Mail->Subject .= ': MIME structure';
1885
$this->Mail->Body = '<h3>MIME structure test.</h3>';
1886
$this->Mail->AltBody = 'MIME structure test.';
1887
$this->buildBody();
1888
$this->Mail->preSend();
1889
self::assertRegExp(
1890
"/Content-Transfer-Encoding: 8bit\r\n\r\n" .
1891
'This is a multi-part message in MIME format./',
1892
$this->Mail->getSentMIMEMessage(),
1893
'MIME structure broken'
1894
);
1895
}
1896
1897
/**
1898
* Test BCC-only addressing.
1899
*/
1900
public function testBCCAddressing()
1901
{
1902
$this->Mail->isSMTP();
1903
$this->Mail->Subject .= ': BCC-only addressing';
1904
$this->buildBody();
1905
$this->Mail->clearAllRecipients();
1906
$this->Mail->addAddress('[email protected]', 'Foo');
1907
$this->Mail->preSend();
1908
$b = $this->Mail->getSentMIMEMessage();
1909
self::assertTrue($this->Mail->addBCC('[email protected]'), 'BCC addressing failed');
1910
self::assertContains('To: Foo <[email protected]>', $b);
1911
self::assertTrue($this->Mail->send(), 'send failed');
1912
}
1913
1914
/**
1915
* Encoding and charset tests.
1916
*/
1917
public function testEncodings()
1918
{
1919
$this->Mail->CharSet = PHPMailer::CHARSET_ISO88591;
1920
self::assertEquals(
1921
'=A1Hola!_Se=F1or!',
1922
$this->Mail->encodeQ("\xa1Hola! Se\xf1or!", 'text'),
1923
'Q Encoding (text) failed'
1924
);
1925
self::assertEquals(
1926
'=A1Hola!_Se=F1or!',
1927
$this->Mail->encodeQ("\xa1Hola! Se\xf1or!", 'comment'),
1928
'Q Encoding (comment) failed'
1929
);
1930
self::assertEquals(
1931
'=A1Hola!_Se=F1or!',
1932
$this->Mail->encodeQ("\xa1Hola! Se\xf1or!", 'phrase'),
1933
'Q Encoding (phrase) failed'
1934
);
1935
$this->Mail->CharSet = 'UTF-8';
1936
self::assertEquals(
1937
'=C2=A1Hola!_Se=C3=B1or!',
1938
$this->Mail->encodeQ("\xc2\xa1Hola! Se\xc3\xb1or!", 'text'),
1939
'Q Encoding (text) failed'
1940
);
1941
//Strings containing '=' are a special case
1942
self::assertEquals(
1943
'Nov=C3=A1=3D',
1944
$this->Mail->encodeQ("Nov\xc3\xa1=", 'text'),
1945
'Q Encoding (text) failed 2'
1946
);
1947
1948
self::assertEquals(
1949
'hello',
1950
$this->Mail->encodeString('hello', 'binary'),
1951
'Binary encoding changed input'
1952
);
1953
$this->Mail->ErrorInfo = '';
1954
$this->Mail->encodeString('hello', 'asdfghjkl');
1955
self::assertNotEmpty($this->Mail->ErrorInfo, 'Invalid encoding not detected');
1956
self::assertRegExp('/' . base64_encode('hello') . '/', $this->Mail->encodeString('hello'));
1957
}
1958
1959
/**
1960
* Expect exceptions on bad encoding
1961
*
1962
* @expectedException PHPMailer\PHPMailer\Exception
1963
*/
1964
public function testAddAttachmentEncodingException()
1965
{
1966
$mail = new PHPMailer(true);
1967
$mail->addAttachment(__FILE__, 'test.txt', 'invalidencoding');
1968
}
1969
1970
/**
1971
* Expect exceptions on sending after deleting a previously successfully attached file
1972
*
1973
* @expectedException PHPMailer\PHPMailer\Exception
1974
*/
1975
public function testDeletedAttachmentException()
1976
{
1977
$filename = __FILE__ . md5(microtime()) . 'test.txt';
1978
touch($filename);
1979
$this->Mail = new PHPMailer(true);
1980
$this->Mail->addAttachment($filename);
1981
unlink($filename);
1982
$this->Mail->send();
1983
}
1984
1985
/**
1986
* Expect error on sending after deleting a previously successfully attached file
1987
*/
1988
public function testDeletedAttachmentError()
1989
{
1990
$filename = __FILE__ . md5(microtime()) . 'test.txt';
1991
touch($filename);
1992
$this->Mail = new PHPMailer();
1993
$this->Mail->addAttachment($filename);
1994
unlink($filename);
1995
self::assertFalse($this->Mail->send());
1996
}
1997
1998
/**
1999
* Expect exceptions on bad encoding
2000
*
2001
* @expectedException PHPMailer\PHPMailer\Exception
2002
*/
2003
public function testStringAttachmentEncodingException()
2004
{
2005
$mail = new PHPMailer(true);
2006
$mail->addStringAttachment('hello', 'test.txt', 'invalidencoding');
2007
}
2008
2009
/**
2010
* Expect exceptions on bad encoding
2011
*
2012
* @expectedException PHPMailer\PHPMailer\Exception
2013
*/
2014
public function testEmbeddedImageEncodingException()
2015
{
2016
$mail = new PHPMailer(true);
2017
$mail->addEmbeddedImage(__FILE__, 'cid', 'test.png', 'invalidencoding');
2018
}
2019
2020
/**
2021
* Expect exceptions on bad encoding
2022
*
2023
* @expectedException PHPMailer\PHPMailer\Exception
2024
*/
2025
public function testStringEmbeddedImageEncodingException()
2026
{
2027
$mail = new PHPMailer(true);
2028
$mail->addStringEmbeddedImage('hello', 'cid', 'test.png', 'invalidencoding');
2029
}
2030
2031
/**
2032
* Test base-64 encoding.
2033
*/
2034
public function testBase64()
2035
{
2036
$this->Mail->Subject .= ': Base-64 encoding';
2037
$this->Mail->Encoding = 'base64';
2038
$this->buildBody();
2039
self::assertTrue($this->Mail->send(), 'Base64 encoding failed');
2040
}
2041
2042
/**
2043
* S/MIME Signing tests (self-signed).
2044
*
2045
* @requires extension openssl
2046
*/
2047
public function testSigning()
2048
{
2049
$this->Mail->Subject .= ': S/MIME signing';
2050
$this->Mail->Body = 'This message is S/MIME signed.';
2051
$this->buildBody();
2052
2053
$dn = [
2054
'countryName' => 'UK',
2055
'stateOrProvinceName' => 'Here',
2056
'localityName' => 'There',
2057
'organizationName' => 'PHP',
2058
'organizationalUnitName' => 'PHPMailer',
2059
'commonName' => 'PHPMailer Test',
2060
'emailAddress' => '[email protected]',
2061
];
2062
$keyconfig = [
2063
'digest_alg' => 'sha256',
2064
'private_key_bits' => 2048,
2065
'private_key_type' => OPENSSL_KEYTYPE_RSA,
2066
];
2067
$password = 'password';
2068
$certfile = 'certfile.pem';
2069
$keyfile = 'keyfile.pem';
2070
2071
//Make a new key pair
2072
$pk = openssl_pkey_new($keyconfig);
2073
//Create a certificate signing request
2074
$csr = openssl_csr_new($dn, $pk);
2075
//Create a self-signed cert
2076
$cert = openssl_csr_sign($csr, null, $pk, 1);
2077
//Save the cert
2078
openssl_x509_export($cert, $certout);
2079
file_put_contents($certfile, $certout);
2080
//Save the key
2081
openssl_pkey_export($pk, $pkeyout, $password);
2082
file_put_contents($keyfile, $pkeyout);
2083
2084
$this->Mail->sign(
2085
$certfile,
2086
$keyfile,
2087
$password
2088
);
2089
self::assertTrue($this->Mail->send(), 'S/MIME signing failed');
2090
2091
$msg = $this->Mail->getSentMIMEMessage();
2092
self::assertNotContains("\r\n\r\nMIME-Version:", $msg, 'Incorrect MIME headers');
2093
unlink($certfile);
2094
unlink($keyfile);
2095
}
2096
2097
/**
2098
* S/MIME Signing tests using a CA chain cert.
2099
* To test that a generated message is signed correctly, save the message in a file called `signed.eml`
2100
* and use openssl along with the certs generated by this script:
2101
* `openssl smime -verify -in signed.eml -signer certfile.pem -CAfile cacertfile.pem`.
2102
*
2103
* @requires extension openssl
2104
*/
2105
public function testSigningWithCA()
2106
{
2107
$this->Mail->Subject .= ': S/MIME signing with CA';
2108
$this->Mail->Body = 'This message is S/MIME signed with an extra CA cert.';
2109
$this->buildBody();
2110
2111
$certprops = [
2112
'countryName' => 'UK',
2113
'stateOrProvinceName' => 'Here',
2114
'localityName' => 'There',
2115
'organizationName' => 'PHP',
2116
'organizationalUnitName' => 'PHPMailer',
2117
'commonName' => 'PHPMailer Test',
2118
'emailAddress' => '[email protected]',
2119
];
2120
$cacertprops = [
2121
'countryName' => 'UK',
2122
'stateOrProvinceName' => 'Here',
2123
'localityName' => 'There',
2124
'organizationName' => 'PHP',
2125
'organizationalUnitName' => 'PHPMailer CA',
2126
'commonName' => 'PHPMailer Test CA',
2127
'emailAddress' => '[email protected]',
2128
];
2129
$keyconfig = [
2130
'digest_alg' => 'sha256',
2131
'private_key_bits' => 2048,
2132
'private_key_type' => OPENSSL_KEYTYPE_RSA,
2133
];
2134
$password = 'password';
2135
$cacertfile = 'cacertfile.pem';
2136
$cakeyfile = 'cakeyfile.pem';
2137
$certfile = 'certfile.pem';
2138
$keyfile = 'keyfile.pem';
2139
2140
//Create a CA cert
2141
//Make a new key pair
2142
$capk = openssl_pkey_new($keyconfig);
2143
//Create a certificate signing request
2144
$csr = openssl_csr_new($cacertprops, $capk);
2145
//Create a self-signed cert
2146
$cert = openssl_csr_sign($csr, null, $capk, 1);
2147
//Save the CA cert
2148
openssl_x509_export($cert, $certout);
2149
file_put_contents($cacertfile, $certout);
2150
//Save the CA key
2151
openssl_pkey_export($capk, $pkeyout, $password);
2152
file_put_contents($cakeyfile, $pkeyout);
2153
2154
//Create a cert signed by our CA
2155
//Make a new key pair
2156
$pk = openssl_pkey_new($keyconfig);
2157
//Create a certificate signing request
2158
$csr = openssl_csr_new($certprops, $pk);
2159
//Create a self-signed cert
2160
$cacert = file_get_contents($cacertfile);
2161
$cert = openssl_csr_sign($csr, $cacert, $capk, 1);
2162
//Save the cert
2163
openssl_x509_export($cert, $certout);
2164
file_put_contents($certfile, $certout);
2165
//Save the key
2166
openssl_pkey_export($pk, $pkeyout, $password);
2167
file_put_contents($keyfile, $pkeyout);
2168
2169
$this->Mail->sign(
2170
$certfile,
2171
$keyfile,
2172
$password,
2173
$cacertfile
2174
);
2175
self::assertTrue($this->Mail->send(), 'S/MIME signing with CA failed');
2176
unlink($cacertfile);
2177
unlink($cakeyfile);
2178
unlink($certfile);
2179
unlink($keyfile);
2180
}
2181
2182
/**
2183
* DKIM body canonicalization tests.
2184
*
2185
* @see https://tools.ietf.org/html/rfc6376#section-3.4.4
2186
*/
2187
public function testDKIMBodyCanonicalization()
2188
{
2189
//Example from https://tools.ietf.org/html/rfc6376#section-3.4.5
2190
$prebody = " C \r\nD \t E\r\n\r\n\r\n";
2191
$postbody = " C \r\nD \t E\r\n";
2192
self::assertEquals($this->Mail->DKIM_BodyC(''), "\r\n", 'DKIM empty body canonicalization incorrect');
2193
self::assertEquals(
2194
'frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN/XKdLCPjaYaY=',
2195
base64_encode(hash('sha256', $this->Mail->DKIM_BodyC(''), true)),
2196
'DKIM canonicalized empty body hash mismatch'
2197
);
2198
self::assertEquals($this->Mail->DKIM_BodyC($prebody), $postbody, 'DKIM body canonicalization incorrect');
2199
}
2200
2201
/**
2202
* DKIM header canonicalization tests.
2203
*
2204
* @see https://tools.ietf.org/html/rfc6376#section-3.4.2
2205
*/
2206
public function testDKIMHeaderCanonicalization()
2207
{
2208
//Example from https://tools.ietf.org/html/rfc6376#section-3.4.5
2209
$preheaders = "A: X\r\nB : Y\t\r\n\tZ \r\n";
2210
$postheaders = "a:X\r\nb:Y Z\r\n";
2211
self::assertEquals(
2212
$postheaders,
2213
$this->Mail->DKIM_HeaderC($preheaders),
2214
'DKIM header canonicalization incorrect'
2215
);
2216
//Check that long folded lines with runs of spaces are canonicalized properly
2217
$preheaders = 'Long-Header-1: <https://example.com/somescript.php?' .
2218
"id=1234567890&name=Abcdefghijklmnopquestuvwxyz&hash=\r\n abc1234\r\n" .
2219
"Long-Header-2: This is a long header value that contains runs of spaces and trailing \r\n" .
2220
' and is folded onto 2 lines';
2221
$postheaders = 'long-header-1:<https://example.com/somescript.php?id=1234567890&' .
2222
"name=Abcdefghijklmnopquestuvwxyz&hash= abc1234\r\nlong-header-2:This is a long" .
2223
' header value that contains runs of spaces and trailing and is folded onto 2 lines';
2224
self::assertEquals(
2225
$postheaders,
2226
$this->Mail->DKIM_HeaderC($preheaders),
2227
'DKIM header canonicalization of long lines incorrect'
2228
);
2229
}
2230
2231
/**
2232
* DKIM copied header fields tests.
2233
*
2234
* @group dkim
2235
*
2236
* @see https://tools.ietf.org/html/rfc6376#section-3.5
2237
*/
2238
public function testDKIMOptionalHeaderFieldsCopy()
2239
{
2240
$privatekeyfile = 'dkim_private.pem';
2241
$pk = openssl_pkey_new(
2242
[
2243
'private_key_bits' => 2048,
2244
'private_key_type' => OPENSSL_KEYTYPE_RSA,
2245
]
2246
);
2247
openssl_pkey_export_to_file($pk, $privatekeyfile);
2248
$this->Mail->DKIM_private = 'dkim_private.pem';
2249
2250
//Example from https://tools.ietf.org/html/rfc6376#section-3.5
2251
$from = '[email protected]';
2252
$to = '[email protected]';
2253
$date = 'date';
2254
$subject = 'example';
2255
2256
$headerLines = "From:$from\r\nTo:$to\r\nDate:$date\r\n";
2257
$copyHeaderFields = " z=From:$from\r\n |To:$to\r\n |Date:$date\r\n |Subject:$subject;\r\n";
2258
2259
$this->Mail->DKIM_copyHeaderFields = true;
2260
self::assertContains(
2261
$copyHeaderFields,
2262
$this->Mail->DKIM_Add($headerLines, $subject, ''),
2263
'DKIM header with copied header fields incorrect'
2264
);
2265
2266
$this->Mail->DKIM_copyHeaderFields = false;
2267
self::assertNotContains(
2268
$copyHeaderFields,
2269
$this->Mail->DKIM_Add($headerLines, $subject, ''),
2270
'DKIM header without copied header fields incorrect'
2271
);
2272
2273
unlink($privatekeyfile);
2274
}
2275
2276
/**
2277
* DKIM signing extra headers tests.
2278
*
2279
* @group dkim
2280
*/
2281
public function testDKIMExtraHeaders()
2282
{
2283
$privatekeyfile = 'dkim_private.pem';
2284
$pk = openssl_pkey_new(
2285
[
2286
'private_key_bits' => 2048,
2287
'private_key_type' => OPENSSL_KEYTYPE_RSA,
2288
]
2289
);
2290
openssl_pkey_export_to_file($pk, $privatekeyfile);
2291
$this->Mail->DKIM_private = 'dkim_private.pem';
2292
2293
//Example from https://tools.ietf.org/html/rfc6376#section-3.5
2294
$from = '[email protected]';
2295
$to = '[email protected]';
2296
$date = 'date';
2297
$subject = 'example';
2298
$anyHeader = 'foo';
2299
$unsubscribeUrl = '<https://www.example.com/unsubscribe/?newsletterId=anytoken&amp;actionToken=anyToken' .
2300
'&otherParam=otherValue&anotherParam=anotherVeryVeryVeryLongValue>';
2301
2302
$this->Mail->addCustomHeader('X-AnyHeader', $anyHeader);
2303
$this->Mail->addCustomHeader('Baz', 'bar');
2304
$this->Mail->addCustomHeader('List-Unsubscribe', $unsubscribeUrl);
2305
2306
$this->Mail->DKIM_extraHeaders = ['Baz', 'List-Unsubscribe'];
2307
2308
$headerLines = "From:$from\r\nTo:$to\r\nDate:$date\r\n";
2309
$headerLines .= "X-AnyHeader:$anyHeader\r\nBaz:bar\r\n";
2310
$headerLines .= 'List-Unsubscribe:' . $this->Mail->encodeHeader($unsubscribeUrl) . "\r\n";
2311
2312
$headerFields = 'h=From:To:Date:Baz:List-Unsubscribe:Subject';
2313
2314
$result = $this->Mail->DKIM_Add($headerLines, $subject, '');
2315
2316
self::assertContains($headerFields, $result, 'DKIM header with extra headers incorrect');
2317
2318
unlink($privatekeyfile);
2319
}
2320
2321
/**
2322
* DKIM Signing tests.
2323
*
2324
* @requires extension openssl
2325
*/
2326
public function testDKIM()
2327
{
2328
$this->Mail->Subject .= ': DKIM signing';
2329
$this->Mail->Body = 'This message is DKIM signed.';
2330
$this->buildBody();
2331
$privatekeyfile = 'dkim_private.pem';
2332
//Make a new key pair
2333
//(2048 bits is the recommended minimum key length -
2334
//gmail won't accept less than 1024 bits)
2335
$pk = openssl_pkey_new(
2336
[
2337
'private_key_bits' => 2048,
2338
'private_key_type' => OPENSSL_KEYTYPE_RSA,
2339
]
2340
);
2341
openssl_pkey_export_to_file($pk, $privatekeyfile);
2342
$this->Mail->DKIM_domain = 'example.com';
2343
$this->Mail->DKIM_private = $privatekeyfile;
2344
$this->Mail->DKIM_selector = 'phpmailer';
2345
$this->Mail->DKIM_passphrase = ''; //key is not encrypted
2346
self::assertTrue($this->Mail->send(), 'DKIM signed mail failed');
2347
$this->Mail->isMail();
2348
self::assertTrue($this->Mail->send(), 'DKIM signed mail via mail() failed');
2349
unlink($privatekeyfile);
2350
}
2351
2352
/**
2353
* Test line break reformatting.
2354
*/
2355
public function testLineBreaks()
2356
{
2357
//May have been altered by earlier tests, can interfere with line break format
2358
$this->Mail->isSMTP();
2359
$this->Mail->preSend();
2360
$unixsrc = "hello\nWorld\nAgain\n";
2361
$macsrc = "hello\rWorld\rAgain\r";
2362
$windowssrc = "hello\r\nWorld\r\nAgain\r\n";
2363
$mixedsrc = "hello\nWorld\rAgain\r\n";
2364
$target = "hello\r\nWorld\r\nAgain\r\n";
2365
self::assertEquals($target, PHPMailer::normalizeBreaks($unixsrc), 'UNIX break reformatting failed');
2366
self::assertEquals($target, PHPMailer::normalizeBreaks($macsrc), 'Mac break reformatting failed');
2367
self::assertEquals($target, PHPMailer::normalizeBreaks($windowssrc), 'Windows break reformatting failed');
2368
self::assertEquals($target, PHPMailer::normalizeBreaks($mixedsrc), 'Mixed break reformatting failed');
2369
2370
//To see accurate results when using postfix, set `sendmail_fix_line_endings = never` in main.cf
2371
$this->Mail->Subject = 'PHPMailer DOS line breaks';
2372
$this->Mail->Body = "This message\r\ncontains\r\nDOS-format\r\nCRLF line breaks.";
2373
self::assertTrue($this->Mail->send());
2374
2375
$this->Mail->Subject = 'PHPMailer UNIX line breaks';
2376
$this->Mail->Body = "This message\ncontains\nUNIX-format\nLF line breaks.";
2377
self::assertTrue($this->Mail->send());
2378
2379
$this->Mail->Encoding = 'quoted-printable';
2380
$this->Mail->Subject = 'PHPMailer DOS line breaks, QP';
2381
$this->Mail->Body = "This message\r\ncontains\r\nDOS-format\r\nCRLF line breaks.";
2382
self::assertTrue($this->Mail->send());
2383
2384
$this->Mail->Subject = 'PHPMailer UNIX line breaks, QP';
2385
$this->Mail->Body = "This message\ncontains\nUNIX-format\nLF line breaks.";
2386
self::assertTrue($this->Mail->send());
2387
}
2388
2389
/**
2390
* Test line length detection.
2391
*/
2392
public function testLineLength()
2393
{
2394
//May have been altered by earlier tests, can interfere with line break format
2395
$this->Mail->isSMTP();
2396
$this->Mail->preSend();
2397
$oklen = str_repeat(str_repeat('0', PHPMailer::MAX_LINE_LENGTH) . "\r\n", 2);
2398
$badlen = str_repeat(str_repeat('1', PHPMailer::MAX_LINE_LENGTH + 1) . "\r\n", 2);
2399
self::assertTrue(PHPMailer::hasLineLongerThanMax($badlen), 'Long line not detected (only)');
2400
self::assertTrue(PHPMailer::hasLineLongerThanMax($oklen . $badlen), 'Long line not detected (first)');
2401
self::assertTrue(PHPMailer::hasLineLongerThanMax($badlen . $oklen), 'Long line not detected (last)');
2402
self::assertTrue(
2403
PHPMailer::hasLineLongerThanMax($oklen . $badlen . $oklen),
2404
'Long line not detected (middle)'
2405
);
2406
self::assertFalse(PHPMailer::hasLineLongerThanMax($oklen), 'Long line false positive');
2407
$this->Mail->isHTML(false);
2408
$this->Mail->Subject .= ': Line length test';
2409
$this->Mail->CharSet = 'UTF-8';
2410
$this->Mail->Encoding = '8bit';
2411
$this->Mail->Body = $oklen . $badlen . $oklen . $badlen;
2412
$this->buildBody();
2413
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
2414
self::assertEquals('quoted-printable', $this->Mail->Encoding, 'Long line did not override transfer encoding');
2415
}
2416
2417
/**
2418
* Test setting and retrieving message ID.
2419
*/
2420
public function testMessageID()
2421
{
2422
$this->Mail->Body = 'Test message ID.';
2423
$id = hash('sha256', 12345);
2424
$this->Mail->MessageID = $id;
2425
$this->buildBody();
2426
$this->Mail->preSend();
2427
$lastid = $this->Mail->getLastMessageID();
2428
self::assertNotEquals($lastid, $id, 'Invalid Message ID allowed');
2429
$id = '<' . hash('sha256', 12345) . '@example.com>';
2430
$this->Mail->MessageID = $id;
2431
$this->buildBody();
2432
$this->Mail->preSend();
2433
$lastid = $this->Mail->getLastMessageID();
2434
self::assertEquals($lastid, $id, 'Custom Message ID not used');
2435
$this->Mail->MessageID = '';
2436
$this->buildBody();
2437
$this->Mail->preSend();
2438
$lastid = $this->Mail->getLastMessageID();
2439
self::assertRegExp('/^<.*@.*>$/', $lastid, 'Invalid default Message ID');
2440
}
2441
2442
/**
2443
* Check whether setting a bad custom header throws exceptions.
2444
*
2445
* @throws Exception
2446
*/
2447
public function testHeaderException()
2448
{
2449
$this->expectException(Exception::class);
2450
$mail = new PHPMailer(true);
2451
$mail->addCustomHeader('SomeHeader', "Some\n Value");
2452
}
2453
2454
/**
2455
* Miscellaneous calls to improve test coverage and some small tests.
2456
*/
2457
public function testMiscellaneous()
2458
{
2459
self::assertEquals('application/pdf', PHPMailer::_mime_types('pdf'), 'MIME TYPE lookup failed');
2460
$this->Mail->clearAttachments();
2461
$this->Mail->isHTML(false);
2462
$this->Mail->isSMTP();
2463
$this->Mail->isMail();
2464
$this->Mail->isSendmail();
2465
$this->Mail->isQmail();
2466
$this->Mail->setLanguage('fr');
2467
$this->Mail->Sender = '';
2468
$this->Mail->createHeader();
2469
self::assertFalse($this->Mail->set('x', 'y'), 'Invalid property set succeeded');
2470
self::assertTrue($this->Mail->set('Timeout', 11), 'Valid property set failed');
2471
self::assertTrue($this->Mail->set('AllowEmpty', null), 'Null property set failed');
2472
self::assertTrue($this->Mail->set('AllowEmpty', false), 'Valid property set of null property failed');
2473
//Test pathinfo
2474
$a = '/mnt/files/飛兒樂 團光茫.mp3';
2475
$q = PHPMailer::mb_pathinfo($a);
2476
self::assertEquals($q['dirname'], '/mnt/files', 'UNIX dirname not matched');
2477
self::assertEquals($q['basename'], '飛兒樂 團光茫.mp3', 'UNIX basename not matched');
2478
self::assertEquals($q['extension'], 'mp3', 'UNIX extension not matched');
2479
self::assertEquals($q['filename'], '飛兒樂 團光茫', 'UNIX filename not matched');
2480
self::assertEquals(
2481
PHPMailer::mb_pathinfo($a, PATHINFO_DIRNAME),
2482
'/mnt/files',
2483
'Dirname path element not matched'
2484
);
2485
self::assertEquals(
2486
PHPMailer::mb_pathinfo($a, PATHINFO_BASENAME),
2487
'飛兒樂 團光茫.mp3',
2488
'Basename path element not matched'
2489
);
2490
self::assertEquals(PHPMailer::mb_pathinfo($a, 'filename'), '飛兒樂 團光茫', 'Filename path element not matched');
2491
$a = 'c:\mnt\files\飛兒樂 團光茫.mp3';
2492
$q = PHPMailer::mb_pathinfo($a);
2493
self::assertEquals($q['dirname'], 'c:\mnt\files', 'Windows dirname not matched');
2494
self::assertEquals($q['basename'], '飛兒樂 團光茫.mp3', 'Windows basename not matched');
2495
self::assertEquals($q['extension'], 'mp3', 'Windows extension not matched');
2496
self::assertEquals($q['filename'], '飛兒樂 團光茫', 'Windows filename not matched');
2497
2498
self::assertEquals(
2499
PHPMailer::filenameToType('abc.jpg?xyz=1'),
2500
'image/jpeg',
2501
'Query string not ignored in filename'
2502
);
2503
self::assertEquals(
2504
PHPMailer::filenameToType('abc.xyzpdq'),
2505
'application/octet-stream',
2506
'Default MIME type not applied to unknown extension'
2507
);
2508
2509
//Line break normalization
2510
$eol = PHPMailer::getLE();
2511
$b1 = "1\r2\r3\r";
2512
$b2 = "1\n2\n3\n";
2513
$b3 = "1\r\n2\r3\n";
2514
$t1 = "1{$eol}2{$eol}3{$eol}";
2515
self::assertEquals(PHPMailer::normalizeBreaks($b1), $t1, 'Failed to normalize line breaks (1)');
2516
self::assertEquals(PHPMailer::normalizeBreaks($b2), $t1, 'Failed to normalize line breaks (2)');
2517
self::assertEquals(PHPMailer::normalizeBreaks($b3), $t1, 'Failed to normalize line breaks (3)');
2518
}
2519
2520
public function testBadSMTP()
2521
{
2522
$this->Mail->smtpConnect();
2523
$smtp = $this->Mail->getSMTPInstance();
2524
self::assertFalse($smtp->mail("somewhere\nbad"), 'Bad SMTP command containing breaks accepted');
2525
}
2526
2527
public function testHostValidation()
2528
{
2529
$good = [
2530
'localhost',
2531
'example.com',
2532
'smtp.gmail.com',
2533
'127.0.0.1',
2534
trim(str_repeat('a0123456789.', 21), '.'),
2535
'[::1]',
2536
'[0:1234:dc0:41:216:3eff:fe67:3e01]',
2537
];
2538
$bad = [
2539
null,
2540
123,
2541
1.5,
2542
new \stdClass(),
2543
[],
2544
'',
2545
'999.0.0.0',
2546
'[1234]',
2547
'[1234:::1]',
2548
trim(str_repeat('a0123456789.', 22), '.'),
2549
'0:1234:dc0:41:216:3eff:fe67:3e01',
2550
'[012q:1234:dc0:41:216:3eff:fe67:3e01]',
2551
'[[::1]]',
2552
];
2553
foreach ($good as $h) {
2554
self::assertTrue(PHPMailer::isValidHost($h), 'Good hostname denied: ' . $h);
2555
}
2556
foreach ($bad as $h) {
2557
self::assertFalse(PHPMailer::isValidHost($h), 'Bad hostname accepted: ' . var_export($h, true));
2558
}
2559
}
2560
2561
/**
2562
* Tests the Custom header getter.
2563
*/
2564
public function testCustomHeaderGetter()
2565
{
2566
$this->Mail->addCustomHeader('foo', 'bar');
2567
self::assertEquals([['foo', 'bar']], $this->Mail->getCustomHeaders());
2568
2569
$this->Mail->addCustomHeader('foo', 'baz');
2570
self::assertEquals(
2571
[
2572
['foo', 'bar'],
2573
['foo', 'baz'],
2574
],
2575
$this->Mail->getCustomHeaders()
2576
);
2577
2578
$this->Mail->clearCustomHeaders();
2579
self::assertEmpty($this->Mail->getCustomHeaders());
2580
2581
$this->Mail->addCustomHeader('yux');
2582
self::assertEquals([['yux', '']], $this->Mail->getCustomHeaders());
2583
2584
$this->Mail->addCustomHeader('Content-Type: application/json');
2585
self::assertEquals(
2586
[
2587
['yux', ''],
2588
['Content-Type', 'application/json'],
2589
],
2590
$this->Mail->getCustomHeaders()
2591
);
2592
$this->Mail->clearCustomHeaders();
2593
$this->Mail->addCustomHeader('SomeHeader: Some Value');
2594
$headers = $this->Mail->getCustomHeaders();
2595
self::assertEquals($headers[0], ['SomeHeader', 'Some Value']);
2596
$this->Mail->clearCustomHeaders();
2597
$this->Mail->addCustomHeader('SomeHeader', 'Some Value');
2598
$headers = $this->Mail->getCustomHeaders();
2599
self::assertEquals($headers[0], ['SomeHeader', 'Some Value']);
2600
$this->Mail->clearCustomHeaders();
2601
self::assertFalse($this->Mail->addCustomHeader('SomeHeader', "Some\n Value"));
2602
self::assertFalse($this->Mail->addCustomHeader("Some\nHeader", 'Some Value'));
2603
}
2604
2605
/**
2606
* Tests setting and retrieving ConfirmReadingTo address, also known as "read receipt" address.
2607
*/
2608
public function testConfirmReadingTo()
2609
{
2610
$this->Mail->CharSet = PHPMailer::CHARSET_UTF8;
2611
$this->buildBody();
2612
2613
$this->Mail->ConfirmReadingTo = '[email protected]'; //Invalid address
2614
self::assertFalse($this->Mail->send(), $this->Mail->ErrorInfo);
2615
2616
$this->Mail->ConfirmReadingTo = ' [email protected]'; //Extra space to trim
2617
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
2618
self::assertEquals(
2619
'[email protected]',
2620
$this->Mail->ConfirmReadingTo,
2621
'Unexpected read receipt address'
2622
);
2623
2624
$this->Mail->ConfirmReadingTo = 'test@françois.ch'; //Address with IDN
2625
if (PHPMailer::idnSupported()) {
2626
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
2627
self::assertEquals(
2628
'[email protected]',
2629
$this->Mail->ConfirmReadingTo,
2630
'IDN address not converted to punycode'
2631
);
2632
} else {
2633
self::assertFalse($this->Mail->send(), $this->Mail->ErrorInfo);
2634
}
2635
}
2636
2637
/**
2638
* Tests CharSet and Unicode -> ASCII conversions for addresses with IDN.
2639
*/
2640
public function testConvertEncoding()
2641
{
2642
if (!PHPMailer::idnSupported()) {
2643
self::markTestSkipped('intl and/or mbstring extensions are not available');
2644
}
2645
2646
$this->Mail->clearAllRecipients();
2647
$this->Mail->clearReplyTos();
2648
2649
// This file is UTF-8 encoded. Create a domain encoded in "iso-8859-1".
2650
$domain = '@' . mb_convert_encoding('françois.ch', 'ISO-8859-1', 'UTF-8');
2651
$this->Mail->addAddress('test' . $domain);
2652
$this->Mail->addCC('test+cc' . $domain);
2653
$this->Mail->addBCC('test+bcc' . $domain);
2654
$this->Mail->addReplyTo('test+replyto' . $domain);
2655
2656
// Queued addresses are not returned by get*Addresses() before send() call.
2657
self::assertEmpty($this->Mail->getToAddresses(), 'Bad "to" recipients');
2658
self::assertEmpty($this->Mail->getCcAddresses(), 'Bad "cc" recipients');
2659
self::assertEmpty($this->Mail->getBccAddresses(), 'Bad "bcc" recipients');
2660
self::assertEmpty($this->Mail->getReplyToAddresses(), 'Bad "reply-to" recipients');
2661
2662
// Clear queued BCC recipient.
2663
$this->Mail->clearBCCs();
2664
2665
$this->buildBody();
2666
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
2667
2668
// Addresses with IDN are returned by get*Addresses() after send() call.
2669
$domain = $this->Mail->punyencodeAddress($domain);
2670
self::assertEquals(
2671
[['test' . $domain, '']],
2672
$this->Mail->getToAddresses(),
2673
'Bad "to" recipients'
2674
);
2675
self::assertEquals(
2676
[['test+cc' . $domain, '']],
2677
$this->Mail->getCcAddresses(),
2678
'Bad "cc" recipients'
2679
);
2680
self::assertEmpty($this->Mail->getBccAddresses(), 'Bad "bcc" recipients');
2681
self::assertEquals(
2682
['test+replyto' . $domain => ['test+replyto' . $domain, '']],
2683
$this->Mail->getReplyToAddresses(),
2684
'Bad "reply-to" addresses'
2685
);
2686
}
2687
2688
/**
2689
* Tests removal of duplicate recipients and reply-tos.
2690
*/
2691
public function testDuplicateIDNRemoved()
2692
{
2693
if (!PHPMailer::idnSupported()) {
2694
self::markTestSkipped('intl and/or mbstring extensions are not available');
2695
}
2696
2697
$this->Mail->clearAllRecipients();
2698
$this->Mail->clearReplyTos();
2699
2700
$this->Mail->CharSet = PHPMailer::CHARSET_UTF8;
2701
2702
self::assertTrue($this->Mail->addAddress('test@françois.ch'));
2703
self::assertFalse($this->Mail->addAddress('test@françois.ch'));
2704
self::assertTrue($this->Mail->addAddress('test@FRANÇOIS.CH'));
2705
self::assertFalse($this->Mail->addAddress('test@FRANÇOIS.CH'));
2706
self::assertTrue($this->Mail->addAddress('[email protected]'));
2707
self::assertFalse($this->Mail->addAddress('[email protected]'));
2708
self::assertFalse($this->Mail->addAddress('[email protected]'));
2709
2710
self::assertTrue($this->Mail->addReplyTo('test+replyto@françois.ch'));
2711
self::assertFalse($this->Mail->addReplyTo('test+replyto@françois.ch'));
2712
self::assertTrue($this->Mail->addReplyTo('test+replyto@FRANÇOIS.CH'));
2713
self::assertFalse($this->Mail->addReplyTo('test+replyto@FRANÇOIS.CH'));
2714
self::assertTrue($this->Mail->addReplyTo('[email protected]'));
2715
self::assertFalse($this->Mail->addReplyTo('[email protected]'));
2716
self::assertFalse($this->Mail->addReplyTo('[email protected]'));
2717
2718
$this->buildBody();
2719
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
2720
2721
// There should be only one "To" address and one "Reply-To" address.
2722
self::assertCount(
2723
1,
2724
$this->Mail->getToAddresses(),
2725
'Bad count of "to" recipients'
2726
);
2727
self::assertCount(
2728
1,
2729
$this->Mail->getReplyToAddresses(),
2730
'Bad count of "reply-to" addresses'
2731
);
2732
}
2733
2734
/**
2735
* Use a fake POP3 server to test POP-before-SMTP auth with a known-good login.
2736
*
2737
* @group pop3
2738
*/
2739
public function testPopBeforeSmtpGood()
2740
{
2741
//Start a fake POP server
2742
$pid = shell_exec(
2743
'/usr/bin/nohup ' .
2744
$this->INCLUDE_DIR .
2745
'/test/runfakepopserver.sh 1100 >/dev/null 2>/dev/null & printf "%u" $!'
2746
);
2747
$this->pids[] = $pid;
2748
2749
sleep(1);
2750
//Test a known-good login
2751
self::assertTrue(
2752
POP3::popBeforeSmtp('localhost', 1100, 10, 'user', 'test', $this->Mail->SMTPDebug),
2753
'POP before SMTP failed'
2754
);
2755
//Kill the fake server, don't care if it fails
2756
@shell_exec('kill -TERM ' . escapeshellarg($pid));
2757
sleep(2);
2758
}
2759
2760
/**
2761
* Use a fake POP3 server to test POP-before-SMTP auth
2762
* with a known-bad login.
2763
*
2764
* @group pop3
2765
*/
2766
public function testPopBeforeSmtpBad()
2767
{
2768
//Start a fake POP server on a different port
2769
//so we don't inadvertently connect to the previous instance
2770
$pid = shell_exec(
2771
'/usr/bin/nohup ' .
2772
$this->INCLUDE_DIR .
2773
'/test/runfakepopserver.sh 1101 >/dev/null 2>/dev/null & printf "%u" $!'
2774
);
2775
$this->pids[] = $pid;
2776
2777
sleep(2);
2778
//Test a known-bad login
2779
self::assertFalse(
2780
POP3::popBeforeSmtp('localhost', 1101, 10, 'user', 'xxx', $this->Mail->SMTPDebug),
2781
'POP before SMTP should have failed'
2782
);
2783
//Kill the fake server, don't care if it fails
2784
@shell_exec('kill -TERM ' . escapeshellarg($pid));
2785
sleep(2);
2786
}
2787
2788
/**
2789
* Test SMTP host connections.
2790
* This test can take a long time, so run it last.
2791
*
2792
* @group slow
2793
*/
2794
public function testSmtpConnect()
2795
{
2796
$this->Mail->SMTPDebug = SMTP::DEBUG_LOWLEVEL; //Show connection-level errors
2797
self::assertTrue($this->Mail->smtpConnect(), 'SMTP single connect failed');
2798
$this->Mail->smtpClose();
2799
2800
// $this->Mail->Host = 'localhost:12345;10.10.10.10:54321;' . $_REQUEST['mail_host'];
2801
// self::assertTrue($this->Mail->smtpConnect(), 'SMTP multi-connect failed');
2802
// $this->Mail->smtpClose();
2803
// $this->Mail->Host = '[::1]:' . $this->Mail->Port . ';' . $_REQUEST['mail_host'];
2804
// self::assertTrue($this->Mail->smtpConnect(), 'SMTP IPv6 literal multi-connect failed');
2805
// $this->Mail->smtpClose();
2806
2807
// All these hosts are expected to fail
2808
// $this->Mail->Host = 'xyz://bogus:25;tls://[bogus]:25;ssl://localhost:12345;tls://localhost:587;10.10.10.10:54321;localhost:12345;10.10.10.10'. $_REQUEST['mail_host'].' ';
2809
// self::assertFalse($this->Mail->smtpConnect());
2810
// $this->Mail->smtpClose();
2811
2812
$this->Mail->Host = ' localhost:12345 ; ' . $_REQUEST['mail_host'] . ' ';
2813
self::assertTrue($this->Mail->smtpConnect(), 'SMTP hosts with stray spaces failed');
2814
$this->Mail->smtpClose();
2815
2816
// Need to pick a harmless option so as not cause problems of its own! socket:bind doesn't work with Travis-CI
2817
$this->Mail->Host = $_REQUEST['mail_host'];
2818
self::assertTrue($this->Mail->smtpConnect(['ssl' => ['verify_depth' => 10]]));
2819
2820
$this->Smtp = $this->Mail->getSMTPInstance();
2821
self::assertInstanceOf(\get_class($this->Smtp), $this->Mail->setSMTPInstance($this->Smtp));
2822
self::assertFalse($this->Smtp->startTLS(), 'SMTP connect with options failed');
2823
self::assertFalse($this->Mail->SMTPAuth);
2824
$this->Mail->smtpClose();
2825
}
2826
2827
/**
2828
* Test OAuth method
2829
*/
2830
public function testOAuth()
2831
{
2832
$PHPMailer = new PHPMailer();
2833
$reflection = new \ReflectionClass($PHPMailer);
2834
$property = $reflection->getProperty('oauth');
2835
$property->setAccessible(true);
2836
$property->setValue($PHPMailer, true);
2837
self::assertTrue($PHPMailer->getOAuth());
2838
2839
$options =[
2840
'provider' => 'dummyprovider',
2841
'userName' => 'dummyusername',
2842
'clientSecret' => 'dummyclientsecret',
2843
'clientId' => 'dummyclientid',
2844
'refreshToken' => 'dummyrefreshtoken',
2845
];
2846
2847
$oauth = new OAuth($options);
2848
self::assertInstanceOf(OAuth::class, $oauth);
2849
$subject = $PHPMailer->setOAuth($oauth);
2850
self::assertNull($subject);
2851
self::assertInstanceOf(OAuth::class, $PHPMailer->getOAuth());
2852
}
2853
2854
/**
2855
* Test ICal method
2856
*/
2857
public function testICalMethod()
2858
{
2859
$this->Mail->Subject .= ': ICal method';
2860
$this->Mail->Body = '<h3>ICal method test.</h3>';
2861
$this->Mail->AltBody = 'ICal method test.';
2862
$this->Mail->Ical = 'BEGIN:VCALENDAR'
2863
. "\r\nVERSION:2.0"
2864
. "\r\nPRODID:-//PHPMailer//PHPMailer Calendar Plugin 1.0//EN"
2865
. "\r\nMETHOD:CANCEL"
2866
. "\r\nCALSCALE:GREGORIAN"
2867
. "\r\nX-MICROSOFT-CALSCALE:GREGORIAN"
2868
. "\r\nBEGIN:VEVENT"
2869
. "\r\nUID:201909250755-42825@test"
2870
. "\r\nDTSTART;20190930T080000Z"
2871
. "\r\nSEQUENCE:2"
2872
. "\r\nTRANSP:OPAQUE"
2873
. "\r\nSTATUS:CONFIRMED"
2874
. "\r\nDTEND:20190930T084500Z"
2875
. "\r\nLOCATION:[London] London Eye"
2876
. "\r\nSUMMARY:Test ICal method"
2877
. "\r\nATTENDEE;CN=Attendee, Test;ROLE=OPT-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP="
2878
. "\r\n TRUE:MAILTO:[email protected]"
2879
. "\r\nCLASS:PUBLIC"
2880
. "\r\nDESCRIPTION:Some plain text"
2881
. "\r\nORGANIZER;CN=\"Example, Test\":MAILTO:[email protected]"
2882
. "\r\nDTSTAMP:20190925T075546Z"
2883
. "\r\nCREATED:20190925T075709Z"
2884
. "\r\nLAST-MODIFIED:20190925T075546Z"
2885
. "\r\nEND:VEVENT"
2886
. "\r\nEND:VCALENDAR";
2887
$this->buildBody();
2888
$this->Mail->preSend();
2889
self::assertRegExp(
2890
'/Content-Type: text\/calendar; method=CANCEL;/',
2891
$this->Mail->getSentMIMEMessage(),
2892
'Wrong ICal method in Content-Type header'
2893
);
2894
}
2895
2896
/**
2897
* Test ICal missing method to use default (REQUEST)
2898
*/
2899
public function testICalInvalidMethod()
2900
{
2901
$this->Mail->Subject .= ': ICal method';
2902
$this->Mail->Body = '<h3>ICal method test.</h3>';
2903
$this->Mail->AltBody = 'ICal method test.';
2904
$this->Mail->Ical = 'BEGIN:VCALENDAR'
2905
. "\r\nVERSION:2.0"
2906
. "\r\nPRODID:-//PHPMailer//PHPMailer Calendar Plugin 1.0//EN"
2907
. "\r\nMETHOD:INVALID"
2908
. "\r\nCALSCALE:GREGORIAN"
2909
. "\r\nX-MICROSOFT-CALSCALE:GREGORIAN"
2910
. "\r\nBEGIN:VEVENT"
2911
. "\r\nUID:201909250755-42825@test"
2912
. "\r\nDTSTART;20190930T080000Z"
2913
. "\r\nSEQUENCE:2"
2914
. "\r\nTRANSP:OPAQUE"
2915
. "\r\nSTATUS:CONFIRMED"
2916
. "\r\nDTEND:20190930T084500Z"
2917
. "\r\nLOCATION:[London] London Eye"
2918
. "\r\nSUMMARY:Test ICal method"
2919
. "\r\nATTENDEE;CN=Attendee, Test;ROLE=OPT-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP="
2920
. "\r\n TRUE:MAILTO:[email protected]"
2921
. "\r\nCLASS:PUBLIC"
2922
. "\r\nDESCRIPTION:Some plain text"
2923
. "\r\nORGANIZER;CN=\"Example, Test\":MAILTO:[email protected]"
2924
. "\r\nDTSTAMP:20190925T075546Z"
2925
. "\r\nCREATED:20190925T075709Z"
2926
. "\r\nLAST-MODIFIED:20190925T075546Z"
2927
. "\r\nEND:VEVENT"
2928
. "\r\nEND:VCALENDAR";
2929
$this->buildBody();
2930
$this->Mail->preSend();
2931
self::assertRegExp(
2932
'/Content-Type: text\/calendar; method=REQUEST;/',
2933
$this->Mail->getSentMIMEMessage(),
2934
'Wrong ICal method in Content-Type header'
2935
);
2936
}
2937
2938
/**
2939
* Test ICal invalid method to use default (REQUEST)
2940
*/
2941
public function testICalDefaultMethod()
2942
{
2943
$this->Mail->Subject .= ': ICal method';
2944
$this->Mail->Body = '<h3>ICal method test.</h3>';
2945
$this->Mail->AltBody = 'ICal method test.';
2946
$this->Mail->Ical = 'BEGIN:VCALENDAR'
2947
. "\r\nVERSION:2.0"
2948
. "\r\nPRODID:-//PHPMailer//PHPMailer Calendar Plugin 1.0//EN"
2949
. "\r\nCALSCALE:GREGORIAN"
2950
. "\r\nX-MICROSOFT-CALSCALE:GREGORIAN"
2951
. "\r\nBEGIN:VEVENT"
2952
. "\r\nUID:201909250755-42825@test"
2953
. "\r\nDTSTART;20190930T080000Z"
2954
. "\r\nSEQUENCE:2"
2955
. "\r\nTRANSP:OPAQUE"
2956
. "\r\nSTATUS:CONFIRMED"
2957
. "\r\nDTEND:20190930T084500Z"
2958
. "\r\nLOCATION:[London] London Eye"
2959
. "\r\nSUMMARY:Test ICal method"
2960
. "\r\nATTENDEE;CN=Attendee, Test;ROLE=OPT-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP="
2961
. "\r\n TRUE:MAILTO:[email protected]"
2962
. "\r\nCLASS:PUBLIC"
2963
. "\r\nDESCRIPTION:Some plain text"
2964
. "\r\nORGANIZER;CN=\"Example, Test\":MAILTO:[email protected]"
2965
. "\r\nDTSTAMP:20190925T075546Z"
2966
. "\r\nCREATED:20190925T075709Z"
2967
. "\r\nLAST-MODIFIED:20190925T075546Z"
2968
. "\r\nEND:VEVENT"
2969
. "\r\nEND:VCALENDAR";
2970
$this->buildBody();
2971
$this->Mail->preSend();
2972
self::assertRegExp(
2973
'/Content-Type: text\/calendar; method=REQUEST;/',
2974
$this->Mail->getSentMIMEMessage(),
2975
'Wrong ICal method in Content-Type header'
2976
);
2977
}
2978
2979
/**
2980
* @test
2981
*/
2982
public function givenIdnAddress_addAddress_returns_true()
2983
{
2984
if (file_exists($this->INCLUDE_DIR . '/test/fakefunctions.php')) {
2985
include $this->INCLUDE_DIR . '/test/fakefunctions.php';
2986
$this->assertTrue($this->Mail->addAddress('test@françois.ch'));
2987
}
2988
}
2989
2990
/**
2991
* @test
2992
*/
2993
public function givenIdnAddress_addReplyTo_returns_true()
2994
{
2995
if (file_exists($this->INCLUDE_DIR . '/test/fakefunctions.php')) {
2996
include $this->INCLUDE_DIR . '/test/fakefunctions.php';
2997
$this->assertTrue($this->Mail->addReplyTo('test@françois.ch'));
2998
}
2999
}
3000
3001
/**
3002
* @test
3003
*/
3004
public function erroneousAddress_addAddress_returns_false()
3005
{
3006
$this->assertFalse($this->Mail->addAddress('mehome.com'));
3007
}
3008
3009
/**
3010
* @test
3011
*/
3012
public function imapParsedAddressList_parseAddress_returnsAddressArray()
3013
{
3014
$expected = [
3015
[
3016
'name' => 'joe',
3017
'address' => '[email protected]',
3018
],
3019
[
3020
'name' => 'me',
3021
'address' => '[email protected]',
3022
],
3023
];
3024
if (file_exists($this->INCLUDE_DIR . '/test/fakefunctions.php')) {
3025
include $this->INCLUDE_DIR . '/test/fakefunctions.php';
3026
$addresses = PHPMailer::parseAddresses('[email protected], [email protected]');
3027
$this->assertEquals(asort($expected), asort($addresses));
3028
}
3029
}
3030
3031
/**
3032
* @test
3033
*/
3034
public function givenIdnAddress_punyencodeAddress_returnsCorrectCode()
3035
{
3036
if (file_exists($this->INCLUDE_DIR . '/test/fakefunctions.php')) {
3037
include $this->INCLUDE_DIR . '/test/fakefunctions.php';
3038
$result = $this->Mail->punyencodeAddress('test@françois.ch');
3039
$this->assertEquals('test@1', $result);
3040
}
3041
}
3042
3043
/**
3044
* @test
3045
*/
3046
public function veryLongWordInMessage_wrapText_returnsWrappedText()
3047
{
3048
$expected = 'Lorem ipsumdolorsitametconsetetursadipscingelitrs=
3049
eddiamnonumy
3050
';
3051
$encodedMessage = 'Lorem ipsumdolorsitametconsetetursadipscingelitrseddiamnonumy';
3052
$result = $this->Mail->wrapText($encodedMessage, 50, true);
3053
$this->assertEquals($result, $expected);
3054
}
3055
3056
/**
3057
* @test
3058
*/
3059
public function encodedText_utf8CharBoundary_returnsCorrectMaxLength()
3060
{
3061
$encodedWordWithMultiByteCharFirstByte = 'H=E4tten';
3062
$encodedSingleByteCharacter = '=0C';
3063
$encodedWordWithMultiByteCharMiddletByte = 'L=C3=B6rem';
3064
3065
$this->assertEquals(1, $this->Mail->utf8CharBoundary($encodedWordWithMultiByteCharFirstByte, 3));
3066
$this->assertEquals(3, $this->Mail->utf8CharBoundary($encodedSingleByteCharacter, 3));
3067
$this->assertEquals(1, $this->Mail->utf8CharBoundary($encodedWordWithMultiByteCharMiddletByte, 6));
3068
}
3069
}
3070
/*
3071
* This is a sample form for setting appropriate test values through a browser
3072
* These values can also be set using a file called testbootstrap.php (not in repo) in the same folder as this script
3073
* which is probably more useful if you run these tests a lot
3074
* <html>
3075
* <body>
3076
* <h3>PHPMailer Unit Test</h3>
3077
* By entering a SMTP hostname it will automatically perform tests with SMTP.
3078
*
3079
* <form name="phpmailer_unit" action=__FILE__ method="get">
3080
* <input type="hidden" name="submitted" value="1"/>
3081
* From Address: <input type="text" size="50" name="mail_from" value="<?php echo get("mail_from"); ?>"/>
3082
* <br/>
3083
* To Address: <input type="text" size="50" name="mail_to" value="<?php echo get("mail_to"); ?>"/>
3084
* <br/>
3085
* Cc Address: <input type="text" size="50" name="mail_cc" value="<?php echo get("mail_cc"); ?>"/>
3086
* <br/>
3087
* SMTP Hostname: <input type="text" size="50" name="mail_host" value="<?php echo get("mail_host"); ?>"/>
3088
* <p/>
3089
* <input type="submit" value="Run Test"/>
3090
*
3091
* </form>
3092
* </body>
3093
* </html>
3094
*/
3095
3096