1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
4
|
|
|
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
5
|
|
|
* |
6
|
|
|
* Licensed under The MIT License |
7
|
|
|
* For full copyright and license information, please see the LICENSE.txt |
8
|
|
|
* Redistributions of files must retain the above copyright notice. |
9
|
|
|
* |
10
|
|
|
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
11
|
|
|
* @link https://cakephp.org CakePHP(tm) Project |
12
|
|
|
* @since 2.0.0 |
13
|
|
|
* @license https://opensource.org/licenses/mit-license.php MIT License |
14
|
|
|
*/ |
15
|
|
|
namespace Cake\Mailer; |
16
|
|
|
|
17
|
|
|
use BadMethodCallException; |
18
|
|
|
use Cake\Core\Configure; |
19
|
|
|
use Cake\Core\StaticConfigTrait; |
20
|
|
|
use Cake\Filesystem\File; |
21
|
|
|
use Cake\Http\Client\FormDataPart; |
22
|
|
|
use Cake\Log\Log; |
23
|
|
|
use Cake\Utility\Hash; |
24
|
|
|
use Cake\Utility\Security; |
25
|
|
|
use Cake\Utility\Text; |
26
|
|
|
use Cake\View\ViewVarsTrait; |
27
|
|
|
use Closure; |
28
|
|
|
use Exception; |
29
|
|
|
use InvalidArgumentException; |
30
|
|
|
use JsonSerializable; |
31
|
|
|
use LogicException; |
32
|
|
|
use PDO; |
33
|
|
|
use RuntimeException; |
34
|
|
|
use Serializable; |
35
|
|
|
use SimpleXMLElement; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* CakePHP Email class. |
39
|
|
|
* |
40
|
|
|
* This class is used for sending Internet Message Format based |
41
|
|
|
* on the standard outlined in https://www.rfc-editor.org/rfc/rfc2822.txt |
42
|
|
|
* |
43
|
|
|
* ### Configuration |
44
|
|
|
* |
45
|
|
|
* Configuration for Email is managed by Email::config() and Email::configTransport(). |
46
|
|
|
* Email::config() can be used to add or read a configuration profile for Email instances. |
47
|
|
|
* Once made configuration profiles can be used to re-use across various email messages your |
48
|
|
|
* application sends. |
49
|
|
|
*/ |
50
|
|
|
class Email implements JsonSerializable, Serializable |
51
|
|
|
{ |
52
|
|
|
use StaticConfigTrait; |
53
|
|
|
use ViewVarsTrait; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Line length - no should more - RFC 2822 - 2.1.1 |
57
|
|
|
* |
58
|
|
|
* @var int |
59
|
|
|
*/ |
60
|
|
|
const LINE_LENGTH_SHOULD = 78; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Line length - no must more - RFC 2822 - 2.1.1 |
64
|
|
|
* |
65
|
|
|
* @var int |
66
|
|
|
*/ |
67
|
|
|
const LINE_LENGTH_MUST = 998; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* Type of message - HTML |
71
|
|
|
* |
72
|
|
|
* @var string |
73
|
|
|
*/ |
74
|
|
|
const MESSAGE_HTML = 'html'; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Type of message - TEXT |
78
|
|
|
* |
79
|
|
|
* @var string |
80
|
|
|
*/ |
81
|
|
|
const MESSAGE_TEXT = 'text'; |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Holds the regex pattern for email validation |
85
|
|
|
* |
86
|
|
|
* @var string |
87
|
|
|
*/ |
88
|
|
|
const EMAIL_PATTERN = '/^((?:[\p{L}0-9.!#$%&\'*+\/=?^_`{|}~-]+)*@[\p{L}0-9-._]+)$/ui'; |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* Recipient of the email |
92
|
|
|
* |
93
|
|
|
* @var array |
94
|
|
|
*/ |
95
|
|
|
protected $_to = []; |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* The mail which the email is sent from |
99
|
|
|
* |
100
|
|
|
* @var array |
101
|
|
|
*/ |
102
|
|
|
protected $_from = []; |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* The sender email |
106
|
|
|
* |
107
|
|
|
* @var array |
108
|
|
|
*/ |
109
|
|
|
protected $_sender = []; |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* The email the recipient will reply to |
113
|
|
|
* |
114
|
|
|
* @var array |
115
|
|
|
*/ |
116
|
|
|
protected $_replyTo = []; |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* The read receipt email |
120
|
|
|
* |
121
|
|
|
* @var array |
122
|
|
|
*/ |
123
|
|
|
protected $_readReceipt = []; |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* The mail that will be used in case of any errors like |
127
|
|
|
* - Remote mailserver down |
128
|
|
|
* - Remote user has exceeded his quota |
129
|
|
|
* - Unknown user |
130
|
|
|
* |
131
|
|
|
* @var array |
132
|
|
|
*/ |
133
|
|
|
protected $_returnPath = []; |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* Carbon Copy |
137
|
|
|
* |
138
|
|
|
* List of email's that should receive a copy of the email. |
139
|
|
|
* The Recipient WILL be able to see this list |
140
|
|
|
* |
141
|
|
|
* @var array |
142
|
|
|
*/ |
143
|
|
|
protected $_cc = []; |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* Blind Carbon Copy |
147
|
|
|
* |
148
|
|
|
* List of email's that should receive a copy of the email. |
149
|
|
|
* The Recipient WILL NOT be able to see this list |
150
|
|
|
* |
151
|
|
|
* @var array |
152
|
|
|
*/ |
153
|
|
|
protected $_bcc = []; |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* Message ID |
157
|
|
|
* |
158
|
|
|
* @var bool|string |
159
|
|
|
*/ |
160
|
|
|
protected $_messageId = true; |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* Domain for messageId generation. |
164
|
|
|
* Needs to be manually set for CLI mailing as env('HTTP_HOST') is empty |
165
|
|
|
* |
166
|
|
|
* @var string |
167
|
|
|
*/ |
168
|
|
|
protected $_domain; |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* The subject of the email |
172
|
|
|
* |
173
|
|
|
* @var string |
174
|
|
|
*/ |
175
|
|
|
protected $_subject = ''; |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* Associative array of a user defined headers |
179
|
|
|
* Keys will be prefixed 'X-' as per RFC2822 Section 4.7.5 |
180
|
|
|
* |
181
|
|
|
* @var array |
182
|
|
|
*/ |
183
|
|
|
protected $_headers = []; |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* Text message |
187
|
|
|
* |
188
|
|
|
* @var string |
189
|
|
|
*/ |
190
|
|
|
protected $_textMessage = ''; |
191
|
|
|
|
192
|
|
|
/** |
193
|
|
|
* Html message |
194
|
|
|
* |
195
|
|
|
* @var string |
196
|
|
|
*/ |
197
|
|
|
protected $_htmlMessage = ''; |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* Final message to send |
201
|
|
|
* |
202
|
|
|
* @var array |
203
|
|
|
*/ |
204
|
|
|
protected $_message = []; |
205
|
|
|
|
206
|
|
|
/** |
207
|
|
|
* Available formats to be sent. |
208
|
|
|
* |
209
|
|
|
* @var array |
210
|
|
|
*/ |
211
|
|
|
protected $_emailFormatAvailable = ['text', 'html', 'both']; |
212
|
|
|
|
213
|
|
|
/** |
214
|
|
|
* What format should the email be sent in |
215
|
|
|
* |
216
|
|
|
* @var string |
217
|
|
|
*/ |
218
|
|
|
protected $_emailFormat = 'text'; |
219
|
|
|
|
220
|
|
|
/** |
221
|
|
|
* The transport instance to use for sending mail. |
222
|
|
|
* |
223
|
|
|
* @var \Cake\Mailer\AbstractTransport|null |
224
|
|
|
*/ |
225
|
|
|
protected $_transport; |
226
|
|
|
|
227
|
|
|
/** |
228
|
|
|
* Charset the email body is sent in |
229
|
|
|
* |
230
|
|
|
* @var string |
231
|
|
|
*/ |
232
|
|
|
public $charset = 'utf-8'; |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* Charset the email header is sent in |
236
|
|
|
* If null, the $charset property will be used as default |
237
|
|
|
* |
238
|
|
|
* @var string|null |
239
|
|
|
*/ |
240
|
|
|
public $headerCharset; |
241
|
|
|
|
242
|
|
|
/** |
243
|
|
|
* The email transfer encoding used. |
244
|
|
|
* If null, the $charset property is used for determined the transfer encoding. |
245
|
|
|
* |
246
|
|
|
* @var string|null |
247
|
|
|
*/ |
248
|
|
|
protected $transferEncoding; |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* Available encoding to be set for transfer. |
252
|
|
|
* |
253
|
|
|
* @var array |
254
|
|
|
*/ |
255
|
|
|
protected $_transferEncodingAvailable = [ |
256
|
|
|
'7bit', |
257
|
|
|
'8bit', |
258
|
|
|
'base64', |
259
|
|
|
'binary', |
260
|
|
|
'quoted-printable', |
261
|
|
|
]; |
262
|
|
|
|
263
|
|
|
/** |
264
|
|
|
* The application wide charset, used to encode headers and body |
265
|
|
|
* |
266
|
|
|
* @var string|null |
267
|
|
|
*/ |
268
|
|
|
protected $_appCharset; |
269
|
|
|
|
270
|
|
|
/** |
271
|
|
|
* List of files that should be attached to the email. |
272
|
|
|
* |
273
|
|
|
* Only absolute paths |
274
|
|
|
* |
275
|
|
|
* @var array |
276
|
|
|
*/ |
277
|
|
|
protected $_attachments = []; |
278
|
|
|
|
279
|
|
|
/** |
280
|
|
|
* If set, boundary to use for multipart mime messages |
281
|
|
|
* |
282
|
|
|
* @var string|null |
283
|
|
|
*/ |
284
|
|
|
protected $_boundary; |
285
|
|
|
|
286
|
|
|
/** |
287
|
|
|
* Contains the optional priority of the email. |
288
|
|
|
* |
289
|
|
|
* @var int|null |
290
|
|
|
*/ |
291
|
|
|
protected $_priority; |
292
|
|
|
|
293
|
|
|
/** |
294
|
|
|
* An array mapping url schemes to fully qualified Transport class names. |
295
|
|
|
* Unused. |
296
|
|
|
* |
297
|
|
|
* @var string[] |
298
|
|
|
* @deprecated 3.7.0 This property is unused and will be removed in 4.0.0. |
299
|
|
|
*/ |
300
|
|
|
protected static $_dsnClassMap = []; |
301
|
|
|
|
302
|
|
|
/** |
303
|
|
|
* A copy of the configuration profile for this |
304
|
|
|
* instance. This copy can be modified with Email::profile(). |
305
|
|
|
* |
306
|
|
|
* @var array |
307
|
|
|
*/ |
308
|
|
|
protected $_profile = []; |
309
|
|
|
|
310
|
|
|
/** |
311
|
|
|
* 8Bit character sets |
312
|
|
|
* |
313
|
|
|
* @var array |
314
|
|
|
*/ |
315
|
|
|
protected $_charset8bit = ['UTF-8', 'SHIFT_JIS']; |
316
|
|
|
|
317
|
|
|
/** |
318
|
|
|
* Define Content-Type charset name |
319
|
|
|
* |
320
|
|
|
* @var array |
321
|
|
|
*/ |
322
|
|
|
protected $_contentTypeCharset = [ |
323
|
|
|
'ISO-2022-JP-MS' => 'ISO-2022-JP', |
324
|
|
|
]; |
325
|
|
|
|
326
|
|
|
/** |
327
|
|
|
* Regex for email validation |
328
|
|
|
* |
329
|
|
|
* If null, filter_var() will be used. Use the emailPattern() method |
330
|
|
|
* to set a custom pattern.' |
331
|
|
|
* |
332
|
|
|
* @var string |
333
|
|
|
*/ |
334
|
|
|
protected $_emailPattern = self::EMAIL_PATTERN; |
335
|
|
|
|
336
|
|
|
/** |
337
|
|
|
* Constructor |
338
|
|
|
* |
339
|
|
|
* @param array|string|null $config Array of configs, or string to load configs from app.php |
340
|
|
|
*/ |
341
|
|
|
public function __construct($config = null) |
342
|
|
|
{ |
343
|
|
|
$this->_appCharset = Configure::read('App.encoding'); |
344
|
|
|
if ($this->_appCharset !== null) { |
345
|
|
|
$this->charset = $this->_appCharset; |
346
|
|
|
} |
347
|
|
|
$this->_domain = preg_replace('/\:\d+$/', '', env('HTTP_HOST')); |
348
|
|
|
if (empty($this->_domain)) { |
349
|
|
|
$this->_domain = php_uname('n'); |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
$this->viewBuilder() |
353
|
|
|
->setClassName('Cake\View\View') |
354
|
|
|
->setTemplate('') |
355
|
|
|
->setLayout('default') |
356
|
|
|
->setHelpers(['Html']); |
357
|
|
|
|
358
|
|
|
if ($config === null) { |
359
|
|
|
$config = static::getConfig('default'); |
360
|
|
|
} |
361
|
|
|
if ($config) { |
362
|
|
|
$this->setProfile($config); |
363
|
|
|
} |
364
|
|
|
if (empty($this->headerCharset)) { |
365
|
|
|
$this->headerCharset = $this->charset; |
366
|
|
|
} |
367
|
|
|
} |
368
|
|
|
|
369
|
|
|
/** |
370
|
|
|
* Clone ViewBuilder instance when email object is cloned. |
371
|
|
|
* |
372
|
|
|
* @return void |
373
|
|
|
*/ |
374
|
|
|
public function __clone() |
375
|
|
|
{ |
376
|
|
|
$this->_viewBuilder = clone $this->viewBuilder(); |
377
|
|
|
} |
378
|
|
|
|
379
|
|
|
/** |
380
|
|
|
* Sets "from" address. |
381
|
|
|
* |
382
|
|
|
* @param string|array $email Null to get, String with email, |
383
|
|
|
* Array with email as key, name as value or email as value (without name) |
384
|
|
|
* @param string|null $name Name |
385
|
|
|
* @return $this |
386
|
|
|
* @throws \InvalidArgumentException |
387
|
|
|
*/ |
388
|
|
|
public function setFrom($email, $name = null) |
389
|
|
|
{ |
390
|
|
|
return $this->_setEmailSingle('_from', $email, $name, 'From requires only 1 email address.'); |
391
|
|
|
} |
392
|
|
|
|
393
|
|
|
/** |
394
|
|
|
* Gets "from" address. |
395
|
|
|
* |
396
|
|
|
* @return array |
397
|
|
|
*/ |
398
|
|
|
public function getFrom() |
399
|
|
|
{ |
400
|
|
|
return $this->_from; |
401
|
|
|
} |
402
|
|
|
|
403
|
|
|
/** |
404
|
|
|
* From |
405
|
|
|
* |
406
|
|
|
* @deprecated 3.4.0 Use setFrom()/getFrom() instead. |
407
|
|
|
* @param string|array|null $email Null to get, String with email, |
408
|
|
|
* Array with email as key, name as value or email as value (without name) |
409
|
|
|
* @param string|null $name Name |
410
|
|
|
* @return array|$this |
411
|
|
|
* @throws \InvalidArgumentException |
412
|
|
|
*/ |
413
|
|
|
public function from($email = null, $name = null) |
414
|
|
|
{ |
415
|
|
|
deprecationWarning('Email::from() is deprecated. Use Email::setFrom() or Email::getFrom() instead.'); |
416
|
|
|
if ($email === null) { |
417
|
|
|
return $this->getFrom(); |
418
|
|
|
} |
419
|
|
|
|
420
|
|
|
return $this->setFrom($email, $name); |
421
|
|
|
} |
422
|
|
|
|
423
|
|
|
/** |
424
|
|
|
* Sets "sender" address. |
425
|
|
|
* |
426
|
|
|
* @param string|array $email String with email, |
427
|
|
|
* Array with email as key, name as value or email as value (without name) |
428
|
|
|
* @param string|null $name Name |
429
|
|
|
* @return $this |
430
|
|
|
* @throws \InvalidArgumentException |
431
|
|
|
*/ |
432
|
|
|
public function setSender($email, $name = null) |
433
|
|
|
{ |
434
|
|
|
return $this->_setEmailSingle('_sender', $email, $name, 'Sender requires only 1 email address.'); |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
/** |
438
|
|
|
* Gets "sender" address. |
439
|
|
|
* |
440
|
|
|
* @return array |
441
|
|
|
*/ |
442
|
|
|
public function getSender() |
443
|
|
|
{ |
444
|
|
|
return $this->_sender; |
445
|
|
|
} |
446
|
|
|
|
447
|
|
|
/** |
448
|
|
|
* Sender |
449
|
|
|
* |
450
|
|
|
* @deprecated 3.4.0 Use setSender()/getSender() instead. |
451
|
|
|
* @param string|array|null $email Null to get, String with email, |
452
|
|
|
* Array with email as key, name as value or email as value (without name) |
453
|
|
|
* @param string|null $name Name |
454
|
|
|
* @return array|$this |
455
|
|
|
* @throws \InvalidArgumentException |
456
|
|
|
*/ |
457
|
|
|
public function sender($email = null, $name = null) |
458
|
|
|
{ |
459
|
|
|
deprecationWarning('Email::sender() is deprecated. Use Email::setSender() or Email::getSender() instead.'); |
460
|
|
|
|
461
|
|
|
if ($email === null) { |
462
|
|
|
return $this->getSender(); |
463
|
|
|
} |
464
|
|
|
|
465
|
|
|
return $this->setSender($email, $name); |
466
|
|
|
} |
467
|
|
|
|
468
|
|
|
/** |
469
|
|
|
* Sets "Reply-To" address. |
470
|
|
|
* |
471
|
|
|
* @param string|array $email String with email, |
472
|
|
|
* Array with email as key, name as value or email as value (without name) |
473
|
|
|
* @param string|null $name Name |
474
|
|
|
* @return $this |
475
|
|
|
* @throws \InvalidArgumentException |
476
|
|
|
*/ |
477
|
|
|
public function setReplyTo($email, $name = null) |
478
|
|
|
{ |
479
|
|
|
return $this->_setEmailSingle('_replyTo', $email, $name, 'Reply-To requires only 1 email address.'); |
480
|
|
|
} |
481
|
|
|
|
482
|
|
|
/** |
483
|
|
|
* Gets "Reply-To" address. |
484
|
|
|
* |
485
|
|
|
* @return array |
486
|
|
|
*/ |
487
|
|
|
public function getReplyTo() |
488
|
|
|
{ |
489
|
|
|
return $this->_replyTo; |
490
|
|
|
} |
491
|
|
|
|
492
|
|
|
/** |
493
|
|
|
* Reply-To |
494
|
|
|
* |
495
|
|
|
* @deprecated 3.4.0 Use setReplyTo()/getReplyTo() instead. |
496
|
|
|
* @param string|array|null $email Null to get, String with email, |
497
|
|
|
* Array with email as key, name as value or email as value (without name) |
498
|
|
|
* @param string|null $name Name |
499
|
|
|
* @return array|$this |
500
|
|
|
* @throws \InvalidArgumentException |
501
|
|
|
*/ |
502
|
|
|
public function replyTo($email = null, $name = null) |
503
|
|
|
{ |
504
|
|
|
deprecationWarning('Email::replyTo() is deprecated. Use Email::setReplyTo() or Email::getReplyTo() instead.'); |
505
|
|
|
|
506
|
|
|
if ($email === null) { |
507
|
|
|
return $this->getReplyTo(); |
508
|
|
|
} |
509
|
|
|
|
510
|
|
|
return $this->setReplyTo($email, $name); |
511
|
|
|
} |
512
|
|
|
|
513
|
|
|
/** |
514
|
|
|
* Sets Read Receipt (Disposition-Notification-To header). |
515
|
|
|
* |
516
|
|
|
* @param string|array $email String with email, |
517
|
|
|
* Array with email as key, name as value or email as value (without name) |
518
|
|
|
* @param string|null $name Name |
519
|
|
|
* @return $this |
520
|
|
|
* @throws \InvalidArgumentException |
521
|
|
|
*/ |
522
|
|
|
public function setReadReceipt($email, $name = null) |
523
|
|
|
{ |
524
|
|
|
return $this->_setEmailSingle('_readReceipt', $email, $name, 'Disposition-Notification-To requires only 1 email address.'); |
525
|
|
|
} |
526
|
|
|
|
527
|
|
|
/** |
528
|
|
|
* Gets Read Receipt (Disposition-Notification-To header). |
529
|
|
|
* |
530
|
|
|
* @return array |
531
|
|
|
*/ |
532
|
|
|
public function getReadReceipt() |
533
|
|
|
{ |
534
|
|
|
return $this->_readReceipt; |
535
|
|
|
} |
536
|
|
|
|
537
|
|
|
/** |
538
|
|
|
* Read Receipt (Disposition-Notification-To header) |
539
|
|
|
* |
540
|
|
|
* @deprecated 3.4.0 Use setReadReceipt()/getReadReceipt() instead. |
541
|
|
|
* @param string|array|null $email Null to get, String with email, |
542
|
|
|
* Array with email as key, name as value or email as value (without name) |
543
|
|
|
* @param string|null $name Name |
544
|
|
|
* @return array|$this |
545
|
|
|
* @throws \InvalidArgumentException |
546
|
|
|
*/ |
547
|
|
|
public function readReceipt($email = null, $name = null) |
548
|
|
|
{ |
549
|
|
|
deprecationWarning('Email::readReceipt() is deprecated. Use Email::setReadReceipt() or Email::getReadReceipt() instead.'); |
550
|
|
|
|
551
|
|
|
if ($email === null) { |
552
|
|
|
return $this->getReadReceipt(); |
553
|
|
|
} |
554
|
|
|
|
555
|
|
|
return $this->setReadReceipt($email, $name); |
556
|
|
|
} |
557
|
|
|
|
558
|
|
|
/** |
559
|
|
|
* Return Path |
560
|
|
|
* |
561
|
|
|
* @param string|array $email String with email, |
562
|
|
|
* Array with email as key, name as value or email as value (without name) |
563
|
|
|
* @param string|null $name Name |
564
|
|
|
* @return $this |
565
|
|
|
* @throws \InvalidArgumentException |
566
|
|
|
*/ |
567
|
|
|
public function setReturnPath($email, $name = null) |
568
|
|
|
{ |
569
|
|
|
return $this->_setEmailSingle('_returnPath', $email, $name, 'Return-Path requires only 1 email address.'); |
570
|
|
|
} |
571
|
|
|
|
572
|
|
|
/** |
573
|
|
|
* Gets return path. |
574
|
|
|
* |
575
|
|
|
* @return array |
576
|
|
|
*/ |
577
|
|
|
public function getReturnPath() |
578
|
|
|
{ |
579
|
|
|
return $this->_returnPath; |
580
|
|
|
} |
581
|
|
|
|
582
|
|
|
/** |
583
|
|
|
* Return Path |
584
|
|
|
* |
585
|
|
|
* @deprecated 3.4.0 Use setReturnPath()/getReturnPath() instead. |
586
|
|
|
* @param string|array|null $email Null to get, String with email, |
587
|
|
|
* Array with email as key, name as value or email as value (without name) |
588
|
|
|
* @param string|null $name Name |
589
|
|
|
* @return array|$this |
590
|
|
|
* @throws \InvalidArgumentException |
591
|
|
|
*/ |
592
|
|
|
public function returnPath($email = null, $name = null) |
593
|
|
|
{ |
594
|
|
|
deprecationWarning('Email::returnPath() is deprecated. Use Email::setReturnPath() or Email::getReturnPath() instead.'); |
595
|
|
|
if ($email === null) { |
596
|
|
|
return $this->getReturnPath(); |
597
|
|
|
} |
598
|
|
|
|
599
|
|
|
return $this->setReturnPath($email, $name); |
600
|
|
|
} |
601
|
|
|
|
602
|
|
|
/** |
603
|
|
|
* Sets "to" address. |
604
|
|
|
* |
605
|
|
|
* @param string|array $email String with email, |
606
|
|
|
* Array with email as key, name as value or email as value (without name) |
607
|
|
|
* @param string|null $name Name |
608
|
|
|
* @return $this |
609
|
|
|
*/ |
610
|
|
|
public function setTo($email, $name = null) |
611
|
|
|
{ |
612
|
|
|
return $this->_setEmail('_to', $email, $name); |
613
|
|
|
} |
614
|
|
|
|
615
|
|
|
/** |
616
|
|
|
* Gets "to" address |
617
|
|
|
* |
618
|
|
|
* @return array |
619
|
|
|
*/ |
620
|
|
|
public function getTo() |
621
|
|
|
{ |
622
|
|
|
return $this->_to; |
623
|
|
|
} |
624
|
|
|
|
625
|
|
|
/** |
626
|
|
|
* To |
627
|
|
|
* |
628
|
|
|
* @deprecated 3.4.0 Use setTo()/getTo() instead. |
629
|
|
|
* @param string|array|null $email Null to get, String with email, |
630
|
|
|
* Array with email as key, name as value or email as value (without name) |
631
|
|
|
* @param string|null $name Name |
632
|
|
|
* @return array|$this |
633
|
|
|
*/ |
634
|
|
|
public function to($email = null, $name = null) |
635
|
|
|
{ |
636
|
|
|
deprecationWarning('Email::to() is deprecated. Use Email::setTo() or Email::getTo() instead.'); |
637
|
|
|
|
638
|
|
|
if ($email === null) { |
639
|
|
|
return $this->getTo(); |
640
|
|
|
} |
641
|
|
|
|
642
|
|
|
return $this->setTo($email, $name); |
643
|
|
|
} |
644
|
|
|
|
645
|
|
|
/** |
646
|
|
|
* Add To |
647
|
|
|
* |
648
|
|
|
* @param string|array $email Null to get, String with email, |
649
|
|
|
* Array with email as key, name as value or email as value (without name) |
650
|
|
|
* @param string|null $name Name |
651
|
|
|
* @return $this |
652
|
|
|
*/ |
653
|
|
|
public function addTo($email, $name = null) |
654
|
|
|
{ |
655
|
|
|
return $this->_addEmail('_to', $email, $name); |
656
|
|
|
} |
657
|
|
|
|
658
|
|
|
/** |
659
|
|
|
* Sets "cc" address. |
660
|
|
|
* |
661
|
|
|
* @param string|array $email String with email, |
662
|
|
|
* Array with email as key, name as value or email as value (without name) |
663
|
|
|
* @param string|null $name Name |
664
|
|
|
* @return $this |
665
|
|
|
*/ |
666
|
|
|
public function setCc($email, $name = null) |
667
|
|
|
{ |
668
|
|
|
return $this->_setEmail('_cc', $email, $name); |
669
|
|
|
} |
670
|
|
|
|
671
|
|
|
/** |
672
|
|
|
* Gets "cc" address. |
673
|
|
|
* |
674
|
|
|
* @return array |
675
|
|
|
*/ |
676
|
|
|
public function getCc() |
677
|
|
|
{ |
678
|
|
|
return $this->_cc; |
679
|
|
|
} |
680
|
|
|
|
681
|
|
|
/** |
682
|
|
|
* Cc |
683
|
|
|
* |
684
|
|
|
* @deprecated 3.4.0 Use setCc()/getCc() instead. |
685
|
|
|
* @param string|array|null $email Null to get, String with email, |
686
|
|
|
* Array with email as key, name as value or email as value (without name) |
687
|
|
|
* @param string|null $name Name |
688
|
|
|
* @return array|$this |
689
|
|
|
*/ |
690
|
|
|
public function cc($email = null, $name = null) |
691
|
|
|
{ |
692
|
|
|
deprecationWarning('Email::cc() is deprecated. Use Email::setCc() or Email::getCc() instead.'); |
693
|
|
|
|
694
|
|
|
if ($email === null) { |
695
|
|
|
return $this->getCc(); |
696
|
|
|
} |
697
|
|
|
|
698
|
|
|
return $this->setCc($email, $name); |
699
|
|
|
} |
700
|
|
|
|
701
|
|
|
/** |
702
|
|
|
* Add Cc |
703
|
|
|
* |
704
|
|
|
* @param string|array $email Null to get, String with email, |
705
|
|
|
* Array with email as key, name as value or email as value (without name) |
706
|
|
|
* @param string|null $name Name |
707
|
|
|
* @return $this |
708
|
|
|
*/ |
709
|
|
|
public function addCc($email, $name = null) |
710
|
|
|
{ |
711
|
|
|
return $this->_addEmail('_cc', $email, $name); |
712
|
|
|
} |
713
|
|
|
|
714
|
|
|
/** |
715
|
|
|
* Sets "bcc" address. |
716
|
|
|
* |
717
|
|
|
* @param string|array $email String with email, |
718
|
|
|
* Array with email as key, name as value or email as value (without name) |
719
|
|
|
* @param string|null $name Name |
720
|
|
|
* @return $this |
721
|
|
|
*/ |
722
|
|
|
public function setBcc($email, $name = null) |
723
|
|
|
{ |
724
|
|
|
return $this->_setEmail('_bcc', $email, $name); |
725
|
|
|
} |
726
|
|
|
|
727
|
|
|
/** |
728
|
|
|
* Gets "bcc" address. |
729
|
|
|
* |
730
|
|
|
* @return array |
731
|
|
|
*/ |
732
|
|
|
public function getBcc() |
733
|
|
|
{ |
734
|
|
|
return $this->_bcc; |
735
|
|
|
} |
736
|
|
|
|
737
|
|
|
/** |
738
|
|
|
* Bcc |
739
|
|
|
* |
740
|
|
|
* @deprecated 3.4.0 Use setBcc()/getBcc() instead. |
741
|
|
|
* @param string|array|null $email Null to get, String with email, |
742
|
|
|
* Array with email as key, name as value or email as value (without name) |
743
|
|
|
* @param string|null $name Name |
744
|
|
|
* @return array|$this |
745
|
|
|
*/ |
746
|
|
|
public function bcc($email = null, $name = null) |
747
|
|
|
{ |
748
|
|
|
deprecationWarning('Email::bcc() is deprecated. Use Email::setBcc() or Email::getBcc() instead.'); |
749
|
|
|
|
750
|
|
|
if ($email === null) { |
751
|
|
|
return $this->getBcc(); |
752
|
|
|
} |
753
|
|
|
|
754
|
|
|
return $this->setBcc($email, $name); |
755
|
|
|
} |
756
|
|
|
|
757
|
|
|
/** |
758
|
|
|
* Add Bcc |
759
|
|
|
* |
760
|
|
|
* @param string|array $email Null to get, String with email, |
761
|
|
|
* Array with email as key, name as value or email as value (without name) |
762
|
|
|
* @param string|null $name Name |
763
|
|
|
* @return $this |
764
|
|
|
*/ |
765
|
|
|
public function addBcc($email, $name = null) |
766
|
|
|
{ |
767
|
|
|
return $this->_addEmail('_bcc', $email, $name); |
768
|
|
|
} |
769
|
|
|
|
770
|
|
|
/** |
771
|
|
|
* Charset setter. |
772
|
|
|
* |
773
|
|
|
* @param string|null $charset Character set. |
774
|
|
|
* @return $this |
775
|
|
|
*/ |
776
|
|
|
public function setCharset($charset) |
777
|
|
|
{ |
778
|
|
|
$this->charset = $charset; |
779
|
|
|
if (!$this->headerCharset) { |
780
|
|
|
$this->headerCharset = $charset; |
781
|
|
|
} |
782
|
|
|
|
783
|
|
|
return $this; |
784
|
|
|
} |
785
|
|
|
|
786
|
|
|
/** |
787
|
|
|
* Charset getter. |
788
|
|
|
* |
789
|
|
|
* @return string Charset |
790
|
|
|
*/ |
791
|
|
|
public function getCharset() |
792
|
|
|
{ |
793
|
|
|
return $this->charset; |
794
|
|
|
} |
795
|
|
|
|
796
|
|
|
/** |
797
|
|
|
* Charset setter/getter |
798
|
|
|
* |
799
|
|
|
* @deprecated 3.4.0 Use setCharset()/getCharset() instead. |
800
|
|
|
* @param string|null $charset Character set. |
801
|
|
|
* @return string Charset |
802
|
|
|
*/ |
803
|
|
|
public function charset($charset = null) |
804
|
|
|
{ |
805
|
|
|
deprecationWarning('Email::charset() is deprecated. Use Email::setCharset() or Email::getCharset() instead.'); |
806
|
|
|
|
807
|
|
|
if ($charset === null) { |
808
|
|
|
return $this->getCharset(); |
809
|
|
|
} |
810
|
|
|
$this->setCharset($charset); |
811
|
|
|
|
812
|
|
|
return $this->charset; |
813
|
|
|
} |
814
|
|
|
|
815
|
|
|
/** |
816
|
|
|
* HeaderCharset setter. |
817
|
|
|
* |
818
|
|
|
* @param string|null $charset Character set. |
819
|
|
|
* @return $this |
820
|
|
|
*/ |
821
|
|
|
public function setHeaderCharset($charset) |
822
|
|
|
{ |
823
|
|
|
$this->headerCharset = $charset; |
824
|
|
|
|
825
|
|
|
return $this; |
826
|
|
|
} |
827
|
|
|
|
828
|
|
|
/** |
829
|
|
|
* HeaderCharset getter. |
830
|
|
|
* |
831
|
|
|
* @return string Charset |
832
|
|
|
*/ |
833
|
|
|
public function getHeaderCharset() |
834
|
|
|
{ |
835
|
|
|
return $this->headerCharset ? $this->headerCharset : $this->charset; |
836
|
|
|
} |
837
|
|
|
|
838
|
|
|
/** |
839
|
|
|
* HeaderCharset setter/getter |
840
|
|
|
* |
841
|
|
|
* @deprecated 3.4.0 Use setHeaderCharset()/getHeaderCharset() instead. |
842
|
|
|
* @param string|null $charset Character set. |
843
|
|
|
* @return string Charset |
844
|
|
|
*/ |
845
|
|
|
public function headerCharset($charset = null) |
846
|
|
|
{ |
847
|
|
|
deprecationWarning('Email::headerCharset() is deprecated. Use Email::setHeaderCharset() or Email::getHeaderCharset() instead.'); |
848
|
|
|
|
849
|
|
|
if ($charset === null) { |
850
|
|
|
return $this->getHeaderCharset(); |
851
|
|
|
} |
852
|
|
|
|
853
|
|
|
$this->setHeaderCharset($charset); |
854
|
|
|
|
855
|
|
|
return $this->headerCharset; |
856
|
|
|
} |
857
|
|
|
|
858
|
|
|
/** |
859
|
|
|
* TransferEncoding setter. |
860
|
|
|
* |
861
|
|
|
* @param string|null $encoding Encoding set. |
862
|
|
|
* @return $this |
863
|
|
|
*/ |
864
|
|
|
public function setTransferEncoding($encoding) |
865
|
|
|
{ |
866
|
|
|
$encoding = strtolower($encoding); |
867
|
|
|
if (!in_array($encoding, $this->_transferEncodingAvailable)) { |
868
|
|
|
throw new InvalidArgumentException( |
869
|
|
|
sprintf( |
870
|
|
|
'Transfer encoding not available. Can be : %s.', |
871
|
|
|
implode(', ', $this->_transferEncodingAvailable) |
872
|
|
|
) |
873
|
|
|
); |
874
|
|
|
} |
875
|
|
|
$this->transferEncoding = $encoding; |
876
|
|
|
|
877
|
|
|
return $this; |
878
|
|
|
} |
879
|
|
|
|
880
|
|
|
/** |
881
|
|
|
* TransferEncoding getter. |
882
|
|
|
* |
883
|
|
|
* @return string|null Encoding |
884
|
|
|
*/ |
885
|
|
|
public function getTransferEncoding() |
886
|
|
|
{ |
887
|
|
|
return $this->transferEncoding; |
888
|
|
|
} |
889
|
|
|
|
890
|
|
|
/** |
891
|
|
|
* EmailPattern setter/getter |
892
|
|
|
* |
893
|
|
|
* @param string|null $regex The pattern to use for email address validation, |
894
|
|
|
* null to unset the pattern and make use of filter_var() instead. |
895
|
|
|
* @return $this |
896
|
|
|
*/ |
897
|
|
|
public function setEmailPattern($regex) |
898
|
|
|
{ |
899
|
|
|
$this->_emailPattern = $regex; |
900
|
|
|
|
901
|
|
|
return $this; |
902
|
|
|
} |
903
|
|
|
|
904
|
|
|
/** |
905
|
|
|
* EmailPattern setter/getter |
906
|
|
|
* |
907
|
|
|
* @return string |
908
|
|
|
*/ |
909
|
|
|
public function getEmailPattern() |
910
|
|
|
{ |
911
|
|
|
return $this->_emailPattern; |
912
|
|
|
} |
913
|
|
|
|
914
|
|
|
/** |
915
|
|
|
* EmailPattern setter/getter |
916
|
|
|
* |
917
|
|
|
* @deprecated 3.4.0 Use setEmailPattern()/getEmailPattern() instead. |
918
|
|
|
* @param string|bool|null $regex The pattern to use for email address validation, |
919
|
|
|
* null to unset the pattern and make use of filter_var() instead, false or |
920
|
|
|
* nothing to return the current value |
921
|
|
|
* @return string|$this |
922
|
|
|
*/ |
923
|
|
|
public function emailPattern($regex = false) |
924
|
|
|
{ |
925
|
|
|
deprecationWarning('Email::emailPattern() is deprecated. Use Email::setEmailPattern() or Email::getEmailPattern() instead.'); |
926
|
|
|
|
927
|
|
|
if ($regex === false) { |
928
|
|
|
return $this->getEmailPattern(); |
929
|
|
|
} |
930
|
|
|
|
931
|
|
|
return $this->setEmailPattern($regex); |
|
|
|
|
932
|
|
|
} |
933
|
|
|
|
934
|
|
|
/** |
935
|
|
|
* Set email |
936
|
|
|
* |
937
|
|
|
* @param string $varName Property name |
938
|
|
|
* @param string|array $email String with email, |
939
|
|
|
* Array with email as key, name as value or email as value (without name) |
940
|
|
|
* @param string $name Name |
941
|
|
|
* @return $this |
942
|
|
|
* @throws \InvalidArgumentException |
943
|
|
|
*/ |
944
|
|
View Code Duplication |
protected function _setEmail($varName, $email, $name) |
945
|
|
|
{ |
946
|
|
|
if (!is_array($email)) { |
947
|
|
|
$this->_validateEmail($email, $varName); |
948
|
|
|
if ($name === null) { |
949
|
|
|
$name = $email; |
950
|
|
|
} |
951
|
|
|
$this->{$varName} = [$email => $name]; |
952
|
|
|
|
953
|
|
|
return $this; |
954
|
|
|
} |
955
|
|
|
$list = []; |
956
|
|
|
foreach ($email as $key => $value) { |
957
|
|
|
if (is_int($key)) { |
958
|
|
|
$key = $value; |
959
|
|
|
} |
960
|
|
|
$this->_validateEmail($key, $varName); |
961
|
|
|
$list[$key] = $value; |
962
|
|
|
} |
963
|
|
|
$this->{$varName} = $list; |
964
|
|
|
|
965
|
|
|
return $this; |
966
|
|
|
} |
967
|
|
|
|
968
|
|
|
/** |
969
|
|
|
* Validate email address |
970
|
|
|
* |
971
|
|
|
* @param string $email Email address to validate |
972
|
|
|
* @param string $context Which property was set |
973
|
|
|
* @return void |
974
|
|
|
* @throws \InvalidArgumentException If email address does not validate |
975
|
|
|
*/ |
976
|
|
|
protected function _validateEmail($email, $context) |
977
|
|
|
{ |
978
|
|
|
if ($this->_emailPattern === null) { |
979
|
|
|
if (filter_var($email, FILTER_VALIDATE_EMAIL)) { |
980
|
|
|
return; |
981
|
|
|
} |
982
|
|
|
} elseif (preg_match($this->_emailPattern, $email)) { |
983
|
|
|
return; |
984
|
|
|
} |
985
|
|
|
|
986
|
|
|
$context = ltrim($context, '_'); |
987
|
|
|
if ($email == '') { |
988
|
|
|
throw new InvalidArgumentException(sprintf('The email set for "%s" is empty.', $context)); |
989
|
|
|
} |
990
|
|
|
throw new InvalidArgumentException(sprintf('Invalid email set for "%s". You passed "%s".', $context, $email)); |
991
|
|
|
} |
992
|
|
|
|
993
|
|
|
/** |
994
|
|
|
* Set only 1 email |
995
|
|
|
* |
996
|
|
|
* @param string $varName Property name |
997
|
|
|
* @param string|array $email String with email, |
998
|
|
|
* Array with email as key, name as value or email as value (without name) |
999
|
|
|
* @param string $name Name |
1000
|
|
|
* @param string $throwMessage Exception message |
1001
|
|
|
* @return $this |
1002
|
|
|
* @throws \InvalidArgumentException |
1003
|
|
|
*/ |
1004
|
|
|
protected function _setEmailSingle($varName, $email, $name, $throwMessage) |
1005
|
|
|
{ |
1006
|
|
|
if ($email === []) { |
1007
|
|
|
$this->{$varName} = $email; |
1008
|
|
|
|
1009
|
|
|
return $this; |
1010
|
|
|
} |
1011
|
|
|
|
1012
|
|
|
$current = $this->{$varName}; |
1013
|
|
|
$this->_setEmail($varName, $email, $name); |
1014
|
|
|
if (count($this->{$varName}) !== 1) { |
1015
|
|
|
$this->{$varName} = $current; |
1016
|
|
|
throw new InvalidArgumentException($throwMessage); |
1017
|
|
|
} |
1018
|
|
|
|
1019
|
|
|
return $this; |
1020
|
|
|
} |
1021
|
|
|
|
1022
|
|
|
/** |
1023
|
|
|
* Add email |
1024
|
|
|
* |
1025
|
|
|
* @param string $varName Property name |
1026
|
|
|
* @param string|array $email String with email, |
1027
|
|
|
* Array with email as key, name as value or email as value (without name) |
1028
|
|
|
* @param string $name Name |
1029
|
|
|
* @return $this |
1030
|
|
|
* @throws \InvalidArgumentException |
1031
|
|
|
*/ |
1032
|
|
View Code Duplication |
protected function _addEmail($varName, $email, $name) |
1033
|
|
|
{ |
1034
|
|
|
if (!is_array($email)) { |
1035
|
|
|
$this->_validateEmail($email, $varName); |
1036
|
|
|
if ($name === null) { |
1037
|
|
|
$name = $email; |
1038
|
|
|
} |
1039
|
|
|
$this->{$varName}[$email] = $name; |
1040
|
|
|
|
1041
|
|
|
return $this; |
1042
|
|
|
} |
1043
|
|
|
$list = []; |
1044
|
|
|
foreach ($email as $key => $value) { |
1045
|
|
|
if (is_int($key)) { |
1046
|
|
|
$key = $value; |
1047
|
|
|
} |
1048
|
|
|
$this->_validateEmail($key, $varName); |
1049
|
|
|
$list[$key] = $value; |
1050
|
|
|
} |
1051
|
|
|
$this->{$varName} = array_merge($this->{$varName}, $list); |
1052
|
|
|
|
1053
|
|
|
return $this; |
1054
|
|
|
} |
1055
|
|
|
|
1056
|
|
|
/** |
1057
|
|
|
* Sets subject. |
1058
|
|
|
* |
1059
|
|
|
* @param string $subject Subject string. |
1060
|
|
|
* @return $this |
1061
|
|
|
*/ |
1062
|
|
|
public function setSubject($subject) |
1063
|
|
|
{ |
1064
|
|
|
$this->_subject = $this->_encode((string)$subject); |
1065
|
|
|
|
1066
|
|
|
return $this; |
1067
|
|
|
} |
1068
|
|
|
|
1069
|
|
|
/** |
1070
|
|
|
* Gets subject. |
1071
|
|
|
* |
1072
|
|
|
* @return string |
1073
|
|
|
*/ |
1074
|
|
|
public function getSubject() |
1075
|
|
|
{ |
1076
|
|
|
return $this->_subject; |
1077
|
|
|
} |
1078
|
|
|
|
1079
|
|
|
/** |
1080
|
|
|
* Get/Set Subject. |
1081
|
|
|
* |
1082
|
|
|
* @deprecated 3.4.0 Use setSubject()/getSubject() instead. |
1083
|
|
|
* @param string|null $subject Subject string. |
1084
|
|
|
* @return string|$this |
1085
|
|
|
*/ |
1086
|
|
|
public function subject($subject = null) |
1087
|
|
|
{ |
1088
|
|
|
deprecationWarning('Email::subject() is deprecated. Use Email::setSubject() or Email::getSubject() instead.'); |
1089
|
|
|
|
1090
|
|
|
if ($subject === null) { |
1091
|
|
|
return $this->getSubject(); |
1092
|
|
|
} |
1093
|
|
|
|
1094
|
|
|
return $this->setSubject($subject); |
1095
|
|
|
} |
1096
|
|
|
|
1097
|
|
|
/** |
1098
|
|
|
* Get original subject without encoding |
1099
|
|
|
* |
1100
|
|
|
* @return string Original subject |
1101
|
|
|
*/ |
1102
|
|
|
public function getOriginalSubject() |
1103
|
|
|
{ |
1104
|
|
|
return $this->_decode($this->_subject); |
1105
|
|
|
} |
1106
|
|
|
|
1107
|
|
|
/** |
1108
|
|
|
* Sets headers for the message |
1109
|
|
|
* |
1110
|
|
|
* @param array $headers Associative array containing headers to be set. |
1111
|
|
|
* @return $this |
1112
|
|
|
*/ |
1113
|
|
|
public function setHeaders(array $headers) |
1114
|
|
|
{ |
1115
|
|
|
$this->_headers = $headers; |
1116
|
|
|
|
1117
|
|
|
return $this; |
1118
|
|
|
} |
1119
|
|
|
|
1120
|
|
|
/** |
1121
|
|
|
* Add header for the message |
1122
|
|
|
* |
1123
|
|
|
* @param array $headers Headers to set. |
1124
|
|
|
* @return $this |
1125
|
|
|
*/ |
1126
|
|
|
public function addHeaders(array $headers) |
1127
|
|
|
{ |
1128
|
|
|
$this->_headers = Hash::merge($this->_headers, $headers); |
1129
|
|
|
|
1130
|
|
|
return $this; |
1131
|
|
|
} |
1132
|
|
|
|
1133
|
|
|
/** |
1134
|
|
|
* Get list of headers |
1135
|
|
|
* |
1136
|
|
|
* ### Includes: |
1137
|
|
|
* |
1138
|
|
|
* - `from` |
1139
|
|
|
* - `replyTo` |
1140
|
|
|
* - `readReceipt` |
1141
|
|
|
* - `returnPath` |
1142
|
|
|
* - `to` |
1143
|
|
|
* - `cc` |
1144
|
|
|
* - `bcc` |
1145
|
|
|
* - `subject` |
1146
|
|
|
* |
1147
|
|
|
* @param array $include List of headers. |
1148
|
|
|
* @return array |
1149
|
|
|
*/ |
1150
|
|
|
public function getHeaders(array $include = []) |
1151
|
|
|
{ |
1152
|
|
|
if ($include == array_values($include)) { |
1153
|
|
|
$include = array_fill_keys($include, true); |
1154
|
|
|
} |
1155
|
|
|
$defaults = array_fill_keys( |
1156
|
|
|
[ |
1157
|
|
|
'from', 'sender', 'replyTo', 'readReceipt', 'returnPath', |
1158
|
|
|
'to', 'cc', 'bcc', 'subject'], |
1159
|
|
|
false |
1160
|
|
|
); |
1161
|
|
|
$include += $defaults; |
1162
|
|
|
|
1163
|
|
|
$headers = []; |
1164
|
|
|
$relation = [ |
1165
|
|
|
'from' => 'From', |
1166
|
|
|
'replyTo' => 'Reply-To', |
1167
|
|
|
'readReceipt' => 'Disposition-Notification-To', |
1168
|
|
|
'returnPath' => 'Return-Path', |
1169
|
|
|
]; |
1170
|
|
|
foreach ($relation as $var => $header) { |
1171
|
|
|
if ($include[$var]) { |
1172
|
|
|
$var = '_' . $var; |
1173
|
|
|
$headers[$header] = current($this->_formatAddress($this->{$var})); |
1174
|
|
|
} |
1175
|
|
|
} |
1176
|
|
|
if ($include['sender']) { |
1177
|
|
|
if (key($this->_sender) === key($this->_from)) { |
1178
|
|
|
$headers['Sender'] = ''; |
1179
|
|
|
} else { |
1180
|
|
|
$headers['Sender'] = current($this->_formatAddress($this->_sender)); |
1181
|
|
|
} |
1182
|
|
|
} |
1183
|
|
|
|
1184
|
|
|
foreach (['to', 'cc', 'bcc'] as $var) { |
1185
|
|
|
if ($include[$var]) { |
1186
|
|
|
$classVar = '_' . $var; |
1187
|
|
|
$headers[ucfirst($var)] = implode(', ', $this->_formatAddress($this->{$classVar})); |
1188
|
|
|
} |
1189
|
|
|
} |
1190
|
|
|
|
1191
|
|
|
$headers += $this->_headers; |
1192
|
|
|
if (!isset($headers['Date'])) { |
1193
|
|
|
$headers['Date'] = date(DATE_RFC2822); |
1194
|
|
|
} |
1195
|
|
|
if ($this->_messageId !== false) { |
1196
|
|
|
if ($this->_messageId === true) { |
1197
|
|
|
$this->_messageId = '<' . str_replace('-', '', Text::uuid()) . '@' . $this->_domain . '>'; |
1198
|
|
|
} |
1199
|
|
|
|
1200
|
|
|
$headers['Message-ID'] = $this->_messageId; |
1201
|
|
|
} |
1202
|
|
|
|
1203
|
|
|
if ($this->_priority) { |
|
|
|
|
1204
|
|
|
$headers['X-Priority'] = $this->_priority; |
1205
|
|
|
} |
1206
|
|
|
|
1207
|
|
|
if ($include['subject']) { |
1208
|
|
|
$headers['Subject'] = $this->_subject; |
1209
|
|
|
} |
1210
|
|
|
|
1211
|
|
|
$headers['MIME-Version'] = '1.0'; |
1212
|
|
|
if ($this->_attachments) { |
|
|
|
|
1213
|
|
|
$headers['Content-Type'] = 'multipart/mixed; boundary="' . $this->_boundary . '"'; |
1214
|
|
|
} elseif ($this->_emailFormat === 'both') { |
1215
|
|
|
$headers['Content-Type'] = 'multipart/alternative; boundary="' . $this->_boundary . '"'; |
1216
|
|
|
} elseif ($this->_emailFormat === 'text') { |
1217
|
|
|
$headers['Content-Type'] = 'text/plain; charset=' . $this->_getContentTypeCharset(); |
1218
|
|
|
} elseif ($this->_emailFormat === 'html') { |
1219
|
|
|
$headers['Content-Type'] = 'text/html; charset=' . $this->_getContentTypeCharset(); |
1220
|
|
|
} |
1221
|
|
|
$headers['Content-Transfer-Encoding'] = $this->_getContentTransferEncoding(); |
1222
|
|
|
|
1223
|
|
|
return $headers; |
1224
|
|
|
} |
1225
|
|
|
|
1226
|
|
|
/** |
1227
|
|
|
* Format addresses |
1228
|
|
|
* |
1229
|
|
|
* If the address contains non alphanumeric/whitespace characters, it will |
1230
|
|
|
* be quoted as characters like `:` and `,` are known to cause issues |
1231
|
|
|
* in address header fields. |
1232
|
|
|
* |
1233
|
|
|
* @param array $address Addresses to format. |
1234
|
|
|
* @return array |
1235
|
|
|
*/ |
1236
|
|
|
protected function _formatAddress($address) |
1237
|
|
|
{ |
1238
|
|
|
$return = []; |
1239
|
|
|
foreach ($address as $email => $alias) { |
1240
|
|
|
if ($email === $alias) { |
1241
|
|
|
$return[] = $email; |
1242
|
|
|
} else { |
1243
|
|
|
$encoded = $this->_encode($alias); |
1244
|
|
|
if ($encoded === $alias && preg_match('/[^a-z0-9 ]/i', $encoded)) { |
1245
|
|
|
$encoded = '"' . str_replace('"', '\"', $encoded) . '"'; |
1246
|
|
|
} |
1247
|
|
|
$return[] = sprintf('%s <%s>', $encoded, $email); |
1248
|
|
|
} |
1249
|
|
|
} |
1250
|
|
|
|
1251
|
|
|
return $return; |
1252
|
|
|
} |
1253
|
|
|
|
1254
|
|
|
/** |
1255
|
|
|
* Sets template. |
1256
|
|
|
* |
1257
|
|
|
* @param string|null $template Template name or null to not use. |
1258
|
|
|
* @return $this |
1259
|
|
|
* @deprecated 3.7.0 Use $email->viewBuilder()->setTemplate() instead. |
1260
|
|
|
*/ |
1261
|
|
|
public function setTemplate($template) |
1262
|
|
|
{ |
1263
|
|
|
deprecationWarning( |
1264
|
|
|
'Email::setTemplate() is deprecated. Use $email->viewBuilder()->setTemplate() instead.' |
1265
|
|
|
); |
1266
|
|
|
|
1267
|
|
|
$this->viewBuilder()->setTemplate($template ?: ''); |
1268
|
|
|
|
1269
|
|
|
return $this; |
1270
|
|
|
} |
1271
|
|
|
|
1272
|
|
|
/** |
1273
|
|
|
* Gets template. |
1274
|
|
|
* |
1275
|
|
|
* @return string |
1276
|
|
|
* @deprecated 3.7.0 Use $email->viewBuilder()->getTemplate() instead. |
1277
|
|
|
*/ |
1278
|
|
|
public function getTemplate() |
1279
|
|
|
{ |
1280
|
|
|
deprecationWarning( |
1281
|
|
|
'Email::getTemplate() is deprecated. Use $email->viewBuilder()->getTemplate() instead.' |
1282
|
|
|
); |
1283
|
|
|
|
1284
|
|
|
return $this->viewBuilder()->getTemplate(); |
1285
|
|
|
} |
1286
|
|
|
|
1287
|
|
|
/** |
1288
|
|
|
* Sets layout. |
1289
|
|
|
* |
1290
|
|
|
* @param string|null $layout Layout name or null to not use |
1291
|
|
|
* @return $this |
1292
|
|
|
* @deprecated 3.7.0 Use $email->viewBuilder()->setLayout() instead. |
1293
|
|
|
*/ |
1294
|
|
|
public function setLayout($layout) |
1295
|
|
|
{ |
1296
|
|
|
deprecationWarning( |
1297
|
|
|
'Email::setLayout() is deprecated. Use $email->viewBuilder()->setLayout() instead.' |
1298
|
|
|
); |
1299
|
|
|
|
1300
|
|
|
$this->viewBuilder()->setLayout($layout ?: false); |
1301
|
|
|
|
1302
|
|
|
return $this; |
1303
|
|
|
} |
1304
|
|
|
|
1305
|
|
|
/** |
1306
|
|
|
* Gets layout. |
1307
|
|
|
* |
1308
|
|
|
* @deprecated 3.7.0 Use $email->viewBuilder()->getLayout() instead. |
1309
|
|
|
* @return string |
1310
|
|
|
*/ |
1311
|
|
|
public function getLayout() |
1312
|
|
|
{ |
1313
|
|
|
deprecationWarning( |
1314
|
|
|
'Email::getLayout() is deprecated. Use $email->viewBuilder()->getLayout() instead.' |
1315
|
|
|
); |
1316
|
|
|
|
1317
|
|
|
return $this->viewBuilder()->getLayout(); |
1318
|
|
|
} |
1319
|
|
|
|
1320
|
|
|
/** |
1321
|
|
|
* Template and layout |
1322
|
|
|
* |
1323
|
|
|
* @deprecated 3.4.0 Use setTemplate()/getTemplate() and setLayout()/getLayout() instead. |
1324
|
|
|
* @param bool|string $template Template name or null to not use |
1325
|
|
|
* @param bool|string $layout Layout name or null to not use |
1326
|
|
|
* @return array|$this |
1327
|
|
|
*/ |
1328
|
|
|
public function template($template = false, $layout = false) |
1329
|
|
|
{ |
1330
|
|
|
deprecationWarning( |
1331
|
|
|
'Email::template() is deprecated. ' . |
1332
|
|
|
'Use $email->viewBuilder()->getTemplate()/setTemplate() ' . |
1333
|
|
|
'and $email->viewBuilder()->getLayout()/setLayout() instead.' |
1334
|
|
|
); |
1335
|
|
|
|
1336
|
|
|
if ($template === false) { |
1337
|
|
|
return [ |
1338
|
|
|
'template' => $this->viewBuilder()->getTemplate(), |
1339
|
|
|
'layout' => $this->viewBuilder()->getLayout(), |
1340
|
|
|
]; |
1341
|
|
|
} |
1342
|
|
|
$this->viewBuilder()->setTemplate($template); |
|
|
|
|
1343
|
|
|
if ($layout !== false) { |
1344
|
|
|
$this->viewBuilder()->setLayout($layout); |
|
|
|
|
1345
|
|
|
} |
1346
|
|
|
|
1347
|
|
|
return $this; |
1348
|
|
|
} |
1349
|
|
|
|
1350
|
|
|
/** |
1351
|
|
|
* Sets view class for render. |
1352
|
|
|
* |
1353
|
|
|
* @param string $viewClass View class name. |
1354
|
|
|
* @return $this |
1355
|
|
|
*/ |
1356
|
|
|
public function setViewRenderer($viewClass) |
1357
|
|
|
{ |
1358
|
|
|
$this->viewBuilder()->setClassName($viewClass); |
1359
|
|
|
|
1360
|
|
|
return $this; |
1361
|
|
|
} |
1362
|
|
|
|
1363
|
|
|
/** |
1364
|
|
|
* Gets view class for render. |
1365
|
|
|
* |
1366
|
|
|
* @return string |
1367
|
|
|
*/ |
1368
|
|
|
public function getViewRenderer() |
1369
|
|
|
{ |
1370
|
|
|
return $this->viewBuilder()->getClassName(); |
1371
|
|
|
} |
1372
|
|
|
|
1373
|
|
|
/** |
1374
|
|
|
* View class for render |
1375
|
|
|
* |
1376
|
|
|
* @deprecated 3.4.0 Use setViewRenderer()/getViewRenderer() instead. |
1377
|
|
|
* @param string|null $viewClass View class name. |
1378
|
|
|
* @return string|$this |
1379
|
|
|
*/ |
1380
|
|
|
public function viewRender($viewClass = null) |
1381
|
|
|
{ |
1382
|
|
|
deprecationWarning('Email::viewRender() is deprecated. Use Email::setViewRenderer() or Email::getViewRenderer() instead.'); |
1383
|
|
|
|
1384
|
|
|
if ($viewClass === null) { |
1385
|
|
|
return $this->getViewRenderer(); |
1386
|
|
|
} |
1387
|
|
|
$this->setViewRenderer($viewClass); |
1388
|
|
|
|
1389
|
|
|
return $this; |
1390
|
|
|
} |
1391
|
|
|
|
1392
|
|
|
/** |
1393
|
|
|
* Sets variables to be set on render. |
1394
|
|
|
* |
1395
|
|
|
* @param array $viewVars Variables to set for view. |
1396
|
|
|
* @return $this |
1397
|
|
|
*/ |
1398
|
|
|
public function setViewVars($viewVars) |
1399
|
|
|
{ |
1400
|
|
|
$this->set((array)$viewVars); |
1401
|
|
|
|
1402
|
|
|
return $this; |
1403
|
|
|
} |
1404
|
|
|
|
1405
|
|
|
/** |
1406
|
|
|
* Gets variables to be set on render. |
1407
|
|
|
* |
1408
|
|
|
* @return array |
1409
|
|
|
*/ |
1410
|
|
|
public function getViewVars() |
1411
|
|
|
{ |
1412
|
|
|
return $this->viewVars; |
1413
|
|
|
} |
1414
|
|
|
|
1415
|
|
|
/** |
1416
|
|
|
* Variables to be set on render |
1417
|
|
|
* |
1418
|
|
|
* @deprecated 3.4.0 Use setViewVars()/getViewVars() instead. |
1419
|
|
|
* @param array|null $viewVars Variables to set for view. |
1420
|
|
|
* @return array|$this |
1421
|
|
|
*/ |
1422
|
|
|
public function viewVars($viewVars = null) |
1423
|
|
|
{ |
1424
|
|
|
deprecationWarning('Email::viewVars() is deprecated. Use Email::setViewVars() or Email::getViewVars() instead.'); |
1425
|
|
|
|
1426
|
|
|
if ($viewVars === null) { |
1427
|
|
|
return $this->getViewVars(); |
1428
|
|
|
} |
1429
|
|
|
|
1430
|
|
|
return $this->setViewVars($viewVars); |
1431
|
|
|
} |
1432
|
|
|
|
1433
|
|
|
/** |
1434
|
|
|
* Sets theme to use when rendering. |
1435
|
|
|
* |
1436
|
|
|
* @param string $theme Theme name. |
1437
|
|
|
* @return $this |
1438
|
|
|
* @deprecated 3.7.0 Use $email->viewBuilder()->setTheme() instead. |
1439
|
|
|
*/ |
1440
|
|
|
public function setTheme($theme) |
1441
|
|
|
{ |
1442
|
|
|
deprecationWarning( |
1443
|
|
|
'Email::setTheme() is deprecated. Use $email->viewBuilder()->setTheme() instead.' |
1444
|
|
|
); |
1445
|
|
|
|
1446
|
|
|
$this->viewBuilder()->setTheme($theme); |
1447
|
|
|
|
1448
|
|
|
return $this; |
1449
|
|
|
} |
1450
|
|
|
|
1451
|
|
|
/** |
1452
|
|
|
* Gets theme to use when rendering. |
1453
|
|
|
* |
1454
|
|
|
* @return string |
1455
|
|
|
* @deprecated 3.7.0 Use $email->viewBuilder()->getTheme() instead. |
1456
|
|
|
*/ |
1457
|
|
|
public function getTheme() |
1458
|
|
|
{ |
1459
|
|
|
deprecationWarning( |
1460
|
|
|
'Email::getTheme() is deprecated. Use $email->viewBuilder()->getTheme() instead.' |
1461
|
|
|
); |
1462
|
|
|
|
1463
|
|
|
return $this->viewBuilder()->getTheme(); |
1464
|
|
|
} |
1465
|
|
|
|
1466
|
|
|
/** |
1467
|
|
|
* Theme to use when rendering |
1468
|
|
|
* |
1469
|
|
|
* @deprecated 3.4.0 Use setTheme()/getTheme() instead. |
1470
|
|
|
* @param string|null $theme Theme name. |
1471
|
|
|
* @return string|$this |
1472
|
|
|
*/ |
1473
|
|
View Code Duplication |
public function theme($theme = null) |
1474
|
|
|
{ |
1475
|
|
|
deprecationWarning( |
1476
|
|
|
'Email::theme() is deprecated. Use $email->viewBuilder()->getTheme()/setTheme() instead.' |
1477
|
|
|
); |
1478
|
|
|
|
1479
|
|
|
if ($theme === null) { |
1480
|
|
|
return $this->viewBuilder()->getTheme(); |
|
|
|
|
1481
|
|
|
} |
1482
|
|
|
|
1483
|
|
|
$this->viewBuilder()->setTheme($theme); |
1484
|
|
|
|
1485
|
|
|
return $this; |
1486
|
|
|
} |
1487
|
|
|
|
1488
|
|
|
/** |
1489
|
|
|
* Sets helpers to be used when rendering. |
1490
|
|
|
* |
1491
|
|
|
* @param array $helpers Helpers list. |
1492
|
|
|
* @return $this |
1493
|
|
|
* @deprecated 3.7.0 Use $email->viewBuilder()->setHelpers() instead. |
1494
|
|
|
*/ |
1495
|
|
|
public function setHelpers(array $helpers) |
1496
|
|
|
{ |
1497
|
|
|
deprecationWarning( |
1498
|
|
|
'Email::setHelpers() is deprecated. Use $email->viewBuilder()->setHelpers() instead.' |
1499
|
|
|
); |
1500
|
|
|
|
1501
|
|
|
$this->viewBuilder()->setHelpers($helpers, false); |
1502
|
|
|
|
1503
|
|
|
return $this; |
1504
|
|
|
} |
1505
|
|
|
|
1506
|
|
|
/** |
1507
|
|
|
* Gets helpers to be used when rendering. |
1508
|
|
|
* |
1509
|
|
|
* @return array |
1510
|
|
|
* @deprecated 3.7.0 Use $email->viewBuilder()->getHelpers() instead. |
1511
|
|
|
*/ |
1512
|
|
|
public function getHelpers() |
1513
|
|
|
{ |
1514
|
|
|
deprecationWarning( |
1515
|
|
|
'Email::getHelpers() is deprecated. Use $email->viewBuilder()->getHelpers() instead.' |
1516
|
|
|
); |
1517
|
|
|
|
1518
|
|
|
return $this->viewBuilder()->getHelpers(); |
1519
|
|
|
} |
1520
|
|
|
|
1521
|
|
|
/** |
1522
|
|
|
* Helpers to be used in render |
1523
|
|
|
* |
1524
|
|
|
* @deprecated 3.4.0 Use setHelpers()/getHelpers() instead. |
1525
|
|
|
* @param array|null $helpers Helpers list. |
1526
|
|
|
* @return array|$this |
1527
|
|
|
*/ |
1528
|
|
|
public function helpers($helpers = null) |
1529
|
|
|
{ |
1530
|
|
|
deprecationWarning( |
1531
|
|
|
'Email::helpers() is deprecated. Use $email->viewBuilder()->getHelpers()/setHelpers() instead.' |
1532
|
|
|
); |
1533
|
|
|
|
1534
|
|
|
if ($helpers === null) { |
1535
|
|
|
return $this->viewBuilder()->getHelpers(); |
1536
|
|
|
} |
1537
|
|
|
|
1538
|
|
|
$this->viewBuilder()->setHelpers((array)$helpers); |
1539
|
|
|
|
1540
|
|
|
return $this; |
1541
|
|
|
} |
1542
|
|
|
|
1543
|
|
|
/** |
1544
|
|
|
* Sets email format. |
1545
|
|
|
* |
1546
|
|
|
* @param string $format Formatting string. |
1547
|
|
|
* @return $this |
1548
|
|
|
* @throws \InvalidArgumentException |
1549
|
|
|
*/ |
1550
|
|
|
public function setEmailFormat($format) |
1551
|
|
|
{ |
1552
|
|
|
if (!in_array($format, $this->_emailFormatAvailable)) { |
1553
|
|
|
throw new InvalidArgumentException('Format not available.'); |
1554
|
|
|
} |
1555
|
|
|
$this->_emailFormat = $format; |
1556
|
|
|
|
1557
|
|
|
return $this; |
1558
|
|
|
} |
1559
|
|
|
|
1560
|
|
|
/** |
1561
|
|
|
* Gets email format. |
1562
|
|
|
* |
1563
|
|
|
* @return string |
1564
|
|
|
*/ |
1565
|
|
|
public function getEmailFormat() |
1566
|
|
|
{ |
1567
|
|
|
return $this->_emailFormat; |
1568
|
|
|
} |
1569
|
|
|
|
1570
|
|
|
/** |
1571
|
|
|
* Email format |
1572
|
|
|
* |
1573
|
|
|
* @deprecated 3.4.0 Use setEmailFormat()/getEmailFormat() instead. |
1574
|
|
|
* @param string|null $format Formatting string. |
1575
|
|
|
* @return string|$this |
1576
|
|
|
* @throws \InvalidArgumentException |
1577
|
|
|
*/ |
1578
|
|
|
public function emailFormat($format = null) |
1579
|
|
|
{ |
1580
|
|
|
deprecationWarning('Email::emailFormat() is deprecated. Use Email::setEmailFormat() or Email::getEmailFormat() instead.'); |
1581
|
|
|
|
1582
|
|
|
if ($format === null) { |
1583
|
|
|
return $this->getEmailFormat(); |
1584
|
|
|
} |
1585
|
|
|
|
1586
|
|
|
return $this->setEmailFormat($format); |
1587
|
|
|
} |
1588
|
|
|
|
1589
|
|
|
/** |
1590
|
|
|
* Sets the transport. |
1591
|
|
|
* |
1592
|
|
|
* When setting the transport you can either use the name |
1593
|
|
|
* of a configured transport or supply a constructed transport. |
1594
|
|
|
* |
1595
|
|
|
* @param string|\Cake\Mailer\AbstractTransport $name Either the name of a configured |
1596
|
|
|
* transport, or a transport instance. |
1597
|
|
|
* @return $this |
1598
|
|
|
* @throws \LogicException When the chosen transport lacks a send method. |
1599
|
|
|
* @throws \InvalidArgumentException When $name is neither a string nor an object. |
1600
|
|
|
*/ |
1601
|
|
|
public function setTransport($name) |
1602
|
|
|
{ |
1603
|
|
|
if (is_string($name)) { |
1604
|
|
|
$transport = TransportFactory::get($name); |
1605
|
|
|
} elseif (is_object($name)) { |
1606
|
|
|
$transport = $name; |
1607
|
|
|
} else { |
1608
|
|
|
throw new InvalidArgumentException( |
1609
|
|
|
sprintf('The value passed for the "$name" argument must be either a string, or an object, %s given.', gettype($name)) |
1610
|
|
|
); |
1611
|
|
|
} |
1612
|
|
|
if (!method_exists($transport, 'send')) { |
1613
|
|
|
throw new LogicException(sprintf('The "%s" do not have send method.', get_class($transport))); |
1614
|
|
|
} |
1615
|
|
|
|
1616
|
|
|
$this->_transport = $transport; |
1617
|
|
|
|
1618
|
|
|
return $this; |
1619
|
|
|
} |
1620
|
|
|
|
1621
|
|
|
/** |
1622
|
|
|
* Gets the transport. |
1623
|
|
|
* |
1624
|
|
|
* @return \Cake\Mailer\AbstractTransport |
1625
|
|
|
*/ |
1626
|
|
|
public function getTransport() |
1627
|
|
|
{ |
1628
|
|
|
return $this->_transport; |
1629
|
|
|
} |
1630
|
|
|
|
1631
|
|
|
/** |
1632
|
|
|
* Get/set the transport. |
1633
|
|
|
* |
1634
|
|
|
* When setting the transport you can either use the name |
1635
|
|
|
* of a configured transport or supply a constructed transport. |
1636
|
|
|
* |
1637
|
|
|
* @deprecated 3.4.0 Use setTransport()/getTransport() instead. |
1638
|
|
|
* @param string|\Cake\Mailer\AbstractTransport|null $name Either the name of a configured |
1639
|
|
|
* transport, or a transport instance. |
1640
|
|
|
* @return \Cake\Mailer\AbstractTransport|$this |
1641
|
|
|
* @throws \LogicException When the chosen transport lacks a send method. |
1642
|
|
|
* @throws \InvalidArgumentException When $name is neither a string nor an object. |
1643
|
|
|
*/ |
1644
|
|
|
public function transport($name = null) |
1645
|
|
|
{ |
1646
|
|
|
deprecationWarning('Email::transport() is deprecated. Use Email::setTransport() or Email::getTransport() instead.'); |
1647
|
|
|
|
1648
|
|
|
if ($name === null) { |
1649
|
|
|
return $this->getTransport(); |
1650
|
|
|
} |
1651
|
|
|
|
1652
|
|
|
return $this->setTransport($name); |
1653
|
|
|
} |
1654
|
|
|
|
1655
|
|
|
/** |
1656
|
|
|
* Sets message ID. |
1657
|
|
|
* |
1658
|
|
|
* @param bool|string $message True to generate a new Message-ID, False to ignore (not send in email), String to set as Message-ID. |
1659
|
|
|
* @return $this |
1660
|
|
|
* @throws \InvalidArgumentException |
1661
|
|
|
*/ |
1662
|
|
|
public function setMessageId($message) |
1663
|
|
|
{ |
1664
|
|
|
if (is_bool($message)) { |
1665
|
|
|
$this->_messageId = $message; |
1666
|
|
|
} else { |
1667
|
|
|
if (!preg_match('/^\<.+@.+\>$/', $message)) { |
1668
|
|
|
throw new InvalidArgumentException('Invalid format to Message-ID. The text should be something like "<[email protected]>"'); |
1669
|
|
|
} |
1670
|
|
|
$this->_messageId = $message; |
1671
|
|
|
} |
1672
|
|
|
|
1673
|
|
|
return $this; |
1674
|
|
|
} |
1675
|
|
|
|
1676
|
|
|
/** |
1677
|
|
|
* Gets message ID. |
1678
|
|
|
* |
1679
|
|
|
* @return bool|string |
1680
|
|
|
*/ |
1681
|
|
|
public function getMessageId() |
1682
|
|
|
{ |
1683
|
|
|
return $this->_messageId; |
1684
|
|
|
} |
1685
|
|
|
|
1686
|
|
|
/** |
1687
|
|
|
* Message-ID |
1688
|
|
|
* |
1689
|
|
|
* @deprecated 3.4.0 Use setMessageId()/getMessageId() instead. |
1690
|
|
|
* @param bool|string|null $message True to generate a new Message-ID, False to ignore (not send in email), String to set as Message-ID |
1691
|
|
|
* @return bool|string|$this |
1692
|
|
|
* @throws \InvalidArgumentException |
1693
|
|
|
*/ |
1694
|
|
|
public function messageId($message = null) |
1695
|
|
|
{ |
1696
|
|
|
deprecationWarning('Email::messageId() is deprecated. Use Email::setMessageId() or Email::getMessageId() instead.'); |
1697
|
|
|
|
1698
|
|
|
if ($message === null) { |
1699
|
|
|
return $this->getMessageId(); |
1700
|
|
|
} |
1701
|
|
|
|
1702
|
|
|
return $this->setMessageId($message); |
1703
|
|
|
} |
1704
|
|
|
|
1705
|
|
|
/** |
1706
|
|
|
* Sets domain. |
1707
|
|
|
* |
1708
|
|
|
* Domain as top level (the part after @). |
1709
|
|
|
* |
1710
|
|
|
* @param string $domain Manually set the domain for CLI mailing. |
1711
|
|
|
* @return $this |
1712
|
|
|
*/ |
1713
|
|
|
public function setDomain($domain) |
1714
|
|
|
{ |
1715
|
|
|
$this->_domain = $domain; |
1716
|
|
|
|
1717
|
|
|
return $this; |
1718
|
|
|
} |
1719
|
|
|
|
1720
|
|
|
/** |
1721
|
|
|
* Gets domain. |
1722
|
|
|
* |
1723
|
|
|
* @return string |
1724
|
|
|
*/ |
1725
|
|
|
public function getDomain() |
1726
|
|
|
{ |
1727
|
|
|
return $this->_domain; |
1728
|
|
|
} |
1729
|
|
|
|
1730
|
|
|
/** |
1731
|
|
|
* Domain as top level (the part after @) |
1732
|
|
|
* |
1733
|
|
|
* @deprecated 3.4.0 Use setDomain()/getDomain() instead. |
1734
|
|
|
* @param string|null $domain Manually set the domain for CLI mailing |
1735
|
|
|
* @return string|$this |
1736
|
|
|
*/ |
1737
|
|
|
public function domain($domain = null) |
1738
|
|
|
{ |
1739
|
|
|
deprecationWarning('Email::domain() is deprecated. Use Email::setDomain() or Email::getDomain() instead.'); |
1740
|
|
|
|
1741
|
|
|
if ($domain === null) { |
1742
|
|
|
return $this->getDomain(); |
1743
|
|
|
} |
1744
|
|
|
|
1745
|
|
|
return $this->setDomain($domain); |
1746
|
|
|
} |
1747
|
|
|
|
1748
|
|
|
/** |
1749
|
|
|
* Add attachments to the email message |
1750
|
|
|
* |
1751
|
|
|
* Attachments can be defined in a few forms depending on how much control you need: |
1752
|
|
|
* |
1753
|
|
|
* Attach a single file: |
1754
|
|
|
* |
1755
|
|
|
* ``` |
1756
|
|
|
* $email->setAttachments('path/to/file'); |
1757
|
|
|
* ``` |
1758
|
|
|
* |
1759
|
|
|
* Attach a file with a different filename: |
1760
|
|
|
* |
1761
|
|
|
* ``` |
1762
|
|
|
* $email->setAttachments(['custom_name.txt' => 'path/to/file.txt']); |
1763
|
|
|
* ``` |
1764
|
|
|
* |
1765
|
|
|
* Attach a file and specify additional properties: |
1766
|
|
|
* |
1767
|
|
|
* ``` |
1768
|
|
|
* $email->setAttachments(['custom_name.png' => [ |
1769
|
|
|
* 'file' => 'path/to/file', |
1770
|
|
|
* 'mimetype' => 'image/png', |
1771
|
|
|
* 'contentId' => 'abc123', |
1772
|
|
|
* 'contentDisposition' => false |
1773
|
|
|
* ] |
1774
|
|
|
* ]); |
1775
|
|
|
* ``` |
1776
|
|
|
* |
1777
|
|
|
* Attach a file from string and specify additional properties: |
1778
|
|
|
* |
1779
|
|
|
* ``` |
1780
|
|
|
* $email->setAttachments(['custom_name.png' => [ |
1781
|
|
|
* 'data' => file_get_contents('path/to/file'), |
1782
|
|
|
* 'mimetype' => 'image/png' |
1783
|
|
|
* ] |
1784
|
|
|
* ]); |
1785
|
|
|
* ``` |
1786
|
|
|
* |
1787
|
|
|
* The `contentId` key allows you to specify an inline attachment. In your email text, you |
1788
|
|
|
* can use `<img src="cid:abc123" />` to display the image inline. |
1789
|
|
|
* |
1790
|
|
|
* The `contentDisposition` key allows you to disable the `Content-Disposition` header, this can improve |
1791
|
|
|
* attachment compatibility with outlook email clients. |
1792
|
|
|
* |
1793
|
|
|
* @param string|array $attachments String with the filename or array with filenames |
1794
|
|
|
* @return $this |
1795
|
|
|
* @throws \InvalidArgumentException |
1796
|
|
|
*/ |
1797
|
|
|
public function setAttachments($attachments) |
1798
|
|
|
{ |
1799
|
|
|
$attach = []; |
1800
|
|
|
foreach ((array)$attachments as $name => $fileInfo) { |
1801
|
|
|
if (!is_array($fileInfo)) { |
1802
|
|
|
$fileInfo = ['file' => $fileInfo]; |
1803
|
|
|
} |
1804
|
|
|
if (!isset($fileInfo['file'])) { |
1805
|
|
|
if (!isset($fileInfo['data'])) { |
1806
|
|
|
throw new InvalidArgumentException('No file or data specified.'); |
1807
|
|
|
} |
1808
|
|
|
if (is_int($name)) { |
1809
|
|
|
throw new InvalidArgumentException('No filename specified.'); |
1810
|
|
|
} |
1811
|
|
|
$fileInfo['data'] = chunk_split(base64_encode($fileInfo['data']), 76, "\r\n"); |
1812
|
|
|
} else { |
1813
|
|
|
$fileName = $fileInfo['file']; |
1814
|
|
|
$fileInfo['file'] = realpath($fileInfo['file']); |
1815
|
|
|
if ($fileInfo['file'] === false || !file_exists($fileInfo['file'])) { |
1816
|
|
|
throw new InvalidArgumentException(sprintf('File not found: "%s"', $fileName)); |
1817
|
|
|
} |
1818
|
|
|
if (is_int($name)) { |
1819
|
|
|
$name = basename($fileInfo['file']); |
1820
|
|
|
} |
1821
|
|
|
} |
1822
|
|
View Code Duplication |
if (!isset($fileInfo['mimetype']) && isset($fileInfo['file']) && function_exists('mime_content_type')) { |
1823
|
|
|
$fileInfo['mimetype'] = mime_content_type($fileInfo['file']); |
1824
|
|
|
} |
1825
|
|
|
if (!isset($fileInfo['mimetype'])) { |
1826
|
|
|
$fileInfo['mimetype'] = 'application/octet-stream'; |
1827
|
|
|
} |
1828
|
|
|
$attach[$name] = $fileInfo; |
1829
|
|
|
} |
1830
|
|
|
$this->_attachments = $attach; |
1831
|
|
|
|
1832
|
|
|
return $this; |
1833
|
|
|
} |
1834
|
|
|
|
1835
|
|
|
/** |
1836
|
|
|
* Gets attachments to the email message. |
1837
|
|
|
* |
1838
|
|
|
* @return array Array of attachments. |
1839
|
|
|
*/ |
1840
|
|
|
public function getAttachments() |
1841
|
|
|
{ |
1842
|
|
|
return $this->_attachments; |
1843
|
|
|
} |
1844
|
|
|
|
1845
|
|
|
/** |
1846
|
|
|
* Add attachments to the email message |
1847
|
|
|
* |
1848
|
|
|
* Attachments can be defined in a few forms depending on how much control you need: |
1849
|
|
|
* |
1850
|
|
|
* Attach a single file: |
1851
|
|
|
* |
1852
|
|
|
* ``` |
1853
|
|
|
* $email->setAttachments('path/to/file'); |
1854
|
|
|
* ``` |
1855
|
|
|
* |
1856
|
|
|
* Attach a file with a different filename: |
1857
|
|
|
* |
1858
|
|
|
* ``` |
1859
|
|
|
* $email->setAttachments(['custom_name.txt' => 'path/to/file.txt']); |
1860
|
|
|
* ``` |
1861
|
|
|
* |
1862
|
|
|
* Attach a file and specify additional properties: |
1863
|
|
|
* |
1864
|
|
|
* ``` |
1865
|
|
|
* $email->setAttachments(['custom_name.png' => [ |
1866
|
|
|
* 'file' => 'path/to/file', |
1867
|
|
|
* 'mimetype' => 'image/png', |
1868
|
|
|
* 'contentId' => 'abc123', |
1869
|
|
|
* 'contentDisposition' => false |
1870
|
|
|
* ] |
1871
|
|
|
* ]); |
1872
|
|
|
* ``` |
1873
|
|
|
* |
1874
|
|
|
* Attach a file from string and specify additional properties: |
1875
|
|
|
* |
1876
|
|
|
* ``` |
1877
|
|
|
* $email->setAttachments(['custom_name.png' => [ |
1878
|
|
|
* 'data' => file_get_contents('path/to/file'), |
1879
|
|
|
* 'mimetype' => 'image/png' |
1880
|
|
|
* ] |
1881
|
|
|
* ]); |
1882
|
|
|
* ``` |
1883
|
|
|
* |
1884
|
|
|
* The `contentId` key allows you to specify an inline attachment. In your email text, you |
1885
|
|
|
* can use `<img src="cid:abc123" />` to display the image inline. |
1886
|
|
|
* |
1887
|
|
|
* The `contentDisposition` key allows you to disable the `Content-Disposition` header, this can improve |
1888
|
|
|
* attachment compatibility with outlook email clients. |
1889
|
|
|
* |
1890
|
|
|
* @deprecated 3.4.0 Use setAttachments()/getAttachments() instead. |
1891
|
|
|
* @param string|array|null $attachments String with the filename or array with filenames |
1892
|
|
|
* @return array|$this Either the array of attachments when getting or $this when setting. |
1893
|
|
|
* @throws \InvalidArgumentException |
1894
|
|
|
*/ |
1895
|
|
|
public function attachments($attachments = null) |
1896
|
|
|
{ |
1897
|
|
|
deprecationWarning('Email::attachments() is deprecated. Use Email::setAttachments() or Email::getAttachments() instead.'); |
1898
|
|
|
|
1899
|
|
|
if ($attachments === null) { |
1900
|
|
|
return $this->getAttachments(); |
1901
|
|
|
} |
1902
|
|
|
|
1903
|
|
|
return $this->setAttachments($attachments); |
1904
|
|
|
} |
1905
|
|
|
|
1906
|
|
|
/** |
1907
|
|
|
* Add attachments |
1908
|
|
|
* |
1909
|
|
|
* @param string|array $attachments String with the filename or array with filenames |
1910
|
|
|
* @return $this |
1911
|
|
|
* @throws \InvalidArgumentException |
1912
|
|
|
* @see \Cake\Mailer\Email::attachments() |
1913
|
|
|
*/ |
1914
|
|
|
public function addAttachments($attachments) |
1915
|
|
|
{ |
1916
|
|
|
$current = $this->_attachments; |
1917
|
|
|
$this->setAttachments($attachments); |
1918
|
|
|
$this->_attachments = array_merge($current, $this->_attachments); |
1919
|
|
|
|
1920
|
|
|
return $this; |
1921
|
|
|
} |
1922
|
|
|
|
1923
|
|
|
/** |
1924
|
|
|
* Get generated message (used by transport classes) |
1925
|
|
|
* |
1926
|
|
|
* @param string|null $type Use MESSAGE_* constants or null to return the full message as array |
1927
|
|
|
* @return string|array String if type is given, array if type is null |
1928
|
|
|
*/ |
1929
|
|
|
public function message($type = null) |
1930
|
|
|
{ |
1931
|
|
|
switch ($type) { |
1932
|
|
|
case static::MESSAGE_HTML: |
1933
|
|
|
return $this->_htmlMessage; |
1934
|
|
|
case static::MESSAGE_TEXT: |
1935
|
|
|
return $this->_textMessage; |
1936
|
|
|
} |
1937
|
|
|
|
1938
|
|
|
return $this->_message; |
1939
|
|
|
} |
1940
|
|
|
|
1941
|
|
|
/** |
1942
|
|
|
* Sets priority. |
1943
|
|
|
* |
1944
|
|
|
* @param int|null $priority 1 (highest) to 5 (lowest) |
1945
|
|
|
* @return $this |
1946
|
|
|
*/ |
1947
|
|
|
public function setPriority($priority) |
1948
|
|
|
{ |
1949
|
|
|
$this->_priority = $priority; |
1950
|
|
|
|
1951
|
|
|
return $this; |
1952
|
|
|
} |
1953
|
|
|
|
1954
|
|
|
/** |
1955
|
|
|
* Gets priority. |
1956
|
|
|
* |
1957
|
|
|
* @return int |
1958
|
|
|
*/ |
1959
|
|
|
public function getPriority() |
1960
|
|
|
{ |
1961
|
|
|
return $this->_priority; |
1962
|
|
|
} |
1963
|
|
|
|
1964
|
|
|
/** |
1965
|
|
|
* Sets transport configuration. |
1966
|
|
|
* |
1967
|
|
|
* Use this method to define transports to use in delivery profiles. |
1968
|
|
|
* Once defined you cannot edit the configurations, and must use |
1969
|
|
|
* Email::dropTransport() to flush the configuration first. |
1970
|
|
|
* |
1971
|
|
|
* When using an array of configuration data a new transport |
1972
|
|
|
* will be constructed for each message sent. When using a Closure, the |
1973
|
|
|
* closure will be evaluated for each message. |
1974
|
|
|
* |
1975
|
|
|
* The `className` is used to define the class to use for a transport. |
1976
|
|
|
* It can either be a short name, or a fully qualified class name |
1977
|
|
|
* |
1978
|
|
|
* @param string|array $key The configuration name to write. Or |
1979
|
|
|
* an array of multiple transports to set. |
1980
|
|
|
* @param array|\Cake\Mailer\AbstractTransport|null $config Either an array of configuration |
1981
|
|
|
* data, or a transport instance. Null when using key as array. |
1982
|
|
|
* @return void |
1983
|
|
|
* @deprecated 3.7.0 Use TransportFactory::setConfig() instead. |
1984
|
|
|
*/ |
1985
|
|
|
public static function setConfigTransport($key, $config = null) |
1986
|
|
|
{ |
1987
|
|
|
deprecationWarning('Email::setConfigTransport() is deprecated. Use TransportFactory::setConfig() instead.'); |
1988
|
|
|
|
1989
|
|
|
TransportFactory::setConfig($key, $config); |
1990
|
|
|
} |
1991
|
|
|
|
1992
|
|
|
/** |
1993
|
|
|
* Gets current transport configuration. |
1994
|
|
|
* |
1995
|
|
|
* @param string $key The configuration name to read. |
1996
|
|
|
* @return array|null Transport config. |
1997
|
|
|
* @deprecated 3.7.0 Use TransportFactory::getConfig() instead. |
1998
|
|
|
*/ |
1999
|
|
|
public static function getConfigTransport($key) |
2000
|
|
|
{ |
2001
|
|
|
deprecationWarning('Email::getConfigTransport() is deprecated. Use TransportFactory::getConfig() instead.'); |
2002
|
|
|
|
2003
|
|
|
return TransportFactory::getConfig($key); |
2004
|
|
|
} |
2005
|
|
|
|
2006
|
|
|
/** |
2007
|
|
|
* Add or read transport configuration. |
2008
|
|
|
* |
2009
|
|
|
* Use this method to define transports to use in delivery profiles. |
2010
|
|
|
* Once defined you cannot edit the configurations, and must use |
2011
|
|
|
* Email::dropTransport() to flush the configuration first. |
2012
|
|
|
* |
2013
|
|
|
* When using an array of configuration data a new transport |
2014
|
|
|
* will be constructed for each message sent. When using a Closure, the |
2015
|
|
|
* closure will be evaluated for each message. |
2016
|
|
|
* |
2017
|
|
|
* The `className` is used to define the class to use for a transport. |
2018
|
|
|
* It can either be a short name, or a fully qualified classname |
2019
|
|
|
* |
2020
|
|
|
* @deprecated 3.4.0 Use TransportFactory::setConfig()/getConfig() instead. |
2021
|
|
|
* @param string|array $key The configuration name to read/write. Or |
2022
|
|
|
* an array of multiple transports to set. |
2023
|
|
|
* @param array|\Cake\Mailer\AbstractTransport|null $config Either an array of configuration |
2024
|
|
|
* data, or a transport instance. |
2025
|
|
|
* @return array|null Either null when setting or an array of data when reading. |
2026
|
|
|
* @throws \BadMethodCallException When modifying an existing configuration. |
2027
|
|
|
*/ |
2028
|
|
|
public static function configTransport($key, $config = null) |
2029
|
|
|
{ |
2030
|
|
|
deprecationWarning('Email::configTransport() is deprecated. Use TransportFactory::setConfig() or TransportFactory::getConfig() instead.'); |
2031
|
|
|
|
2032
|
|
|
if ($config === null && is_string($key)) { |
2033
|
|
|
return TransportFactory::getConfig($key); |
2034
|
|
|
} |
2035
|
|
|
if ($config === null && is_array($key)) { |
2036
|
|
|
TransportFactory::setConfig($key); |
2037
|
|
|
|
2038
|
|
|
return null; |
2039
|
|
|
} |
2040
|
|
|
|
2041
|
|
|
TransportFactory::setConfig($key, $config); |
2042
|
|
|
} |
2043
|
|
|
|
2044
|
|
|
/** |
2045
|
|
|
* Returns an array containing the named transport configurations |
2046
|
|
|
* |
2047
|
|
|
* @return array Array of configurations. |
2048
|
|
|
* @deprecated 3.7.0 Use TransportFactory::configured() instead. |
2049
|
|
|
*/ |
2050
|
|
|
public static function configuredTransport() |
2051
|
|
|
{ |
2052
|
|
|
deprecationWarning('Email::configuredTransport() is deprecated. Use TransportFactory::configured().'); |
2053
|
|
|
|
2054
|
|
|
return TransportFactory::configured(); |
2055
|
|
|
} |
2056
|
|
|
|
2057
|
|
|
/** |
2058
|
|
|
* Delete transport configuration. |
2059
|
|
|
* |
2060
|
|
|
* @param string $key The transport name to remove. |
2061
|
|
|
* @return void |
2062
|
|
|
* @deprecated 3.7.0 Use TransportFactory::drop() instead. |
2063
|
|
|
*/ |
2064
|
|
|
public static function dropTransport($key) |
2065
|
|
|
{ |
2066
|
|
|
deprecationWarning('Email::dropTransport() is deprecated. Use TransportFactory::drop().'); |
2067
|
|
|
|
2068
|
|
|
TransportFactory::drop($key); |
2069
|
|
|
} |
2070
|
|
|
|
2071
|
|
|
/** |
2072
|
|
|
* Sets the configuration profile to use for this instance. |
2073
|
|
|
* |
2074
|
|
|
* @param string|array $config String with configuration name, or |
2075
|
|
|
* an array with config. |
2076
|
|
|
* @return $this |
2077
|
|
|
*/ |
2078
|
|
|
public function setProfile($config) |
2079
|
|
|
{ |
2080
|
|
|
if (!is_array($config)) { |
2081
|
|
|
$config = (string)$config; |
2082
|
|
|
} |
2083
|
|
|
$this->_applyConfig($config); |
2084
|
|
|
|
2085
|
|
|
return $this; |
2086
|
|
|
} |
2087
|
|
|
|
2088
|
|
|
/** |
2089
|
|
|
* Gets the configuration profile to use for this instance. |
2090
|
|
|
* |
2091
|
|
|
* @return string|array |
2092
|
|
|
*/ |
2093
|
|
|
public function getProfile() |
2094
|
|
|
{ |
2095
|
|
|
return $this->_profile; |
2096
|
|
|
} |
2097
|
|
|
|
2098
|
|
|
/** |
2099
|
|
|
* Get/Set the configuration profile to use for this instance. |
2100
|
|
|
* |
2101
|
|
|
* @deprecated 3.4.0 Use setProfile()/getProfile() instead. |
2102
|
|
|
* @param array|string|null $config String with configuration name, or |
2103
|
|
|
* an array with config or null to return current config. |
2104
|
|
|
* @return string|array|$this |
2105
|
|
|
*/ |
2106
|
|
|
public function profile($config = null) |
2107
|
|
|
{ |
2108
|
|
|
deprecationWarning('Email::profile() is deprecated. Use Email::setProfile() or Email::getProfile() instead.'); |
2109
|
|
|
|
2110
|
|
|
if ($config === null) { |
2111
|
|
|
return $this->getProfile(); |
2112
|
|
|
} |
2113
|
|
|
|
2114
|
|
|
return $this->setProfile($config); |
2115
|
|
|
} |
2116
|
|
|
|
2117
|
|
|
/** |
2118
|
|
|
* Send an email using the specified content, template and layout |
2119
|
|
|
* |
2120
|
|
|
* @param string|array|null $content String with message or array with messages |
2121
|
|
|
* @return array |
2122
|
|
|
* @throws \BadMethodCallException |
2123
|
|
|
*/ |
2124
|
|
|
public function send($content = null) |
2125
|
|
|
{ |
2126
|
|
|
if (empty($this->_from)) { |
2127
|
|
|
throw new BadMethodCallException('From is not specified.'); |
2128
|
|
|
} |
2129
|
|
|
if (empty($this->_to) && empty($this->_cc) && empty($this->_bcc)) { |
2130
|
|
|
throw new BadMethodCallException('You need specify one destination on to, cc or bcc.'); |
2131
|
|
|
} |
2132
|
|
|
|
2133
|
|
|
if (is_array($content)) { |
2134
|
|
|
$content = implode("\n", $content) . "\n"; |
2135
|
|
|
} |
2136
|
|
|
|
2137
|
|
|
$this->_message = $this->_render($this->_wrap($content)); |
2138
|
|
|
|
2139
|
|
|
$transport = $this->getTransport(); |
2140
|
|
|
if (!$transport) { |
2141
|
|
|
$msg = 'Cannot send email, transport was not defined. Did you call transport() or define ' . |
2142
|
|
|
' a transport in the set profile?'; |
2143
|
|
|
throw new BadMethodCallException($msg); |
2144
|
|
|
} |
2145
|
|
|
$contents = $transport->send($this); |
2146
|
|
|
$this->_logDelivery($contents); |
2147
|
|
|
|
2148
|
|
|
return $contents; |
2149
|
|
|
} |
2150
|
|
|
|
2151
|
|
|
/** |
2152
|
|
|
* Log the email message delivery. |
2153
|
|
|
* |
2154
|
|
|
* @param array $contents The content with 'headers' and 'message' keys. |
2155
|
|
|
* @return void |
2156
|
|
|
*/ |
2157
|
|
|
protected function _logDelivery($contents) |
2158
|
|
|
{ |
2159
|
|
|
if (empty($this->_profile['log'])) { |
2160
|
|
|
return; |
2161
|
|
|
} |
2162
|
|
|
$config = [ |
2163
|
|
|
'level' => 'debug', |
2164
|
|
|
'scope' => 'email', |
2165
|
|
|
]; |
2166
|
|
|
if ($this->_profile['log'] !== true) { |
2167
|
|
|
if (!is_array($this->_profile['log'])) { |
2168
|
|
|
$this->_profile['log'] = ['level' => $this->_profile['log']]; |
2169
|
|
|
} |
2170
|
|
|
$config = $this->_profile['log'] + $config; |
2171
|
|
|
} |
2172
|
|
|
Log::write( |
2173
|
|
|
$config['level'], |
2174
|
|
|
PHP_EOL . $this->flatten($contents['headers']) . PHP_EOL . PHP_EOL . $this->flatten($contents['message']), |
2175
|
|
|
$config['scope'] |
2176
|
|
|
); |
2177
|
|
|
} |
2178
|
|
|
|
2179
|
|
|
/** |
2180
|
|
|
* Converts given value to string |
2181
|
|
|
* |
2182
|
|
|
* @param string|array $value The value to convert |
2183
|
|
|
* @return string |
2184
|
|
|
*/ |
2185
|
|
|
protected function flatten($value) |
2186
|
|
|
{ |
2187
|
|
|
return is_array($value) ? implode(';', $value) : (string)$value; |
2188
|
|
|
} |
2189
|
|
|
|
2190
|
|
|
/** |
2191
|
|
|
* Static method to fast create an instance of \Cake\Mailer\Email |
2192
|
|
|
* |
2193
|
|
|
* @param string|array|null $to Address to send (see Cake\Mailer\Email::to()). If null, will try to use 'to' from transport config |
2194
|
|
|
* @param string|null $subject String of subject or null to use 'subject' from transport config |
2195
|
|
|
* @param string|array|null $message String with message or array with variables to be used in render |
2196
|
|
|
* @param string|array $config String to use Email delivery profile from app.php or array with configs |
2197
|
|
|
* @param bool $send Send the email or just return the instance pre-configured |
2198
|
|
|
* @return static Instance of Cake\Mailer\Email |
2199
|
|
|
* @throws \InvalidArgumentException |
2200
|
|
|
*/ |
2201
|
|
|
public static function deliver($to = null, $subject = null, $message = null, $config = 'default', $send = true) |
2202
|
|
|
{ |
2203
|
|
|
$class = __CLASS__; |
2204
|
|
|
|
2205
|
|
|
if (is_array($config) && !isset($config['transport'])) { |
2206
|
|
|
$config['transport'] = 'default'; |
2207
|
|
|
} |
2208
|
|
|
/** @var \Cake\Mailer\Email $instance */ |
2209
|
|
|
$instance = new $class($config); |
2210
|
|
|
if ($to !== null) { |
2211
|
|
|
$instance->setTo($to); |
2212
|
|
|
} |
2213
|
|
|
if ($subject !== null) { |
2214
|
|
|
$instance->setSubject($subject); |
2215
|
|
|
} |
2216
|
|
|
if (is_array($message)) { |
2217
|
|
|
$instance->setViewVars($message); |
2218
|
|
|
$message = null; |
2219
|
|
|
} elseif ($message === null && array_key_exists('message', $config = $instance->getProfile())) { |
2220
|
|
|
$message = $config['message']; |
2221
|
|
|
} |
2222
|
|
|
|
2223
|
|
|
if ($send === true) { |
2224
|
|
|
$instance->send($message); |
2225
|
|
|
} |
2226
|
|
|
|
2227
|
|
|
return $instance; |
2228
|
|
|
} |
2229
|
|
|
|
2230
|
|
|
/** |
2231
|
|
|
* Apply the config to an instance |
2232
|
|
|
* |
2233
|
|
|
* @param string|array $config Configuration options. |
2234
|
|
|
* @return void |
2235
|
|
|
* @throws \InvalidArgumentException When using a configuration that doesn't exist. |
2236
|
|
|
*/ |
2237
|
|
|
protected function _applyConfig($config) |
2238
|
|
|
{ |
2239
|
|
|
if (is_string($config)) { |
2240
|
|
|
$name = $config; |
2241
|
|
|
$config = static::getConfig($name); |
2242
|
|
|
if (empty($config)) { |
2243
|
|
|
throw new InvalidArgumentException(sprintf('Unknown email configuration "%s".', $name)); |
2244
|
|
|
} |
2245
|
|
|
unset($name); |
2246
|
|
|
} |
2247
|
|
|
|
2248
|
|
|
$this->_profile = array_merge($this->_profile, $config); |
2249
|
|
|
|
2250
|
|
|
$simpleMethods = [ |
2251
|
|
|
'from', 'sender', 'to', 'replyTo', 'readReceipt', 'returnPath', |
2252
|
|
|
'cc', 'bcc', 'messageId', 'domain', 'subject', 'attachments', |
2253
|
|
|
'transport', 'emailFormat', 'emailPattern', 'charset', 'headerCharset', |
2254
|
|
|
]; |
2255
|
|
|
foreach ($simpleMethods as $method) { |
2256
|
|
|
if (isset($config[$method])) { |
2257
|
|
|
$this->{'set' . ucfirst($method)}($config[$method]); |
2258
|
|
|
} |
2259
|
|
|
} |
2260
|
|
|
|
2261
|
|
|
if (empty($this->headerCharset)) { |
2262
|
|
|
$this->headerCharset = $this->charset; |
2263
|
|
|
} |
2264
|
|
|
if (isset($config['headers'])) { |
2265
|
|
|
$this->setHeaders($config['headers']); |
2266
|
|
|
} |
2267
|
|
|
|
2268
|
|
|
$viewBuilderMethods = [ |
2269
|
|
|
'template', 'layout', 'theme', |
2270
|
|
|
]; |
2271
|
|
|
foreach ($viewBuilderMethods as $method) { |
2272
|
|
|
if (array_key_exists($method, $config)) { |
2273
|
|
|
$this->viewBuilder()->{'set' . ucfirst($method)}($config[$method]); |
2274
|
|
|
} |
2275
|
|
|
} |
2276
|
|
|
|
2277
|
|
|
if (array_key_exists('helpers', $config)) { |
2278
|
|
|
$this->viewBuilder()->setHelpers($config['helpers'], false); |
2279
|
|
|
} |
2280
|
|
|
if (array_key_exists('viewRender', $config)) { |
2281
|
|
|
$this->viewBuilder()->setClassName($config['viewRender']); |
2282
|
|
|
} |
2283
|
|
|
if (array_key_exists('viewVars', $config)) { |
2284
|
|
|
$this->set($config['viewVars']); |
2285
|
|
|
} |
2286
|
|
|
} |
2287
|
|
|
|
2288
|
|
|
/** |
2289
|
|
|
* Reset all the internal variables to be able to send out a new email. |
2290
|
|
|
* |
2291
|
|
|
* @return $this |
2292
|
|
|
*/ |
2293
|
|
|
public function reset() |
2294
|
|
|
{ |
2295
|
|
|
$this->_to = []; |
2296
|
|
|
$this->_from = []; |
2297
|
|
|
$this->_sender = []; |
2298
|
|
|
$this->_replyTo = []; |
2299
|
|
|
$this->_readReceipt = []; |
2300
|
|
|
$this->_returnPath = []; |
2301
|
|
|
$this->_cc = []; |
2302
|
|
|
$this->_bcc = []; |
2303
|
|
|
$this->_messageId = true; |
2304
|
|
|
$this->_subject = ''; |
2305
|
|
|
$this->_headers = []; |
2306
|
|
|
$this->_textMessage = ''; |
2307
|
|
|
$this->_htmlMessage = ''; |
2308
|
|
|
$this->_message = []; |
2309
|
|
|
$this->_emailFormat = 'text'; |
2310
|
|
|
$this->_transport = null; |
2311
|
|
|
$this->_priority = null; |
2312
|
|
|
$this->charset = 'utf-8'; |
2313
|
|
|
$this->headerCharset = null; |
2314
|
|
|
$this->transferEncoding = null; |
2315
|
|
|
$this->_attachments = []; |
2316
|
|
|
$this->_profile = []; |
2317
|
|
|
$this->_emailPattern = self::EMAIL_PATTERN; |
2318
|
|
|
|
2319
|
|
|
$this->viewBuilder()->setLayout('default'); |
2320
|
|
|
$this->viewBuilder()->setTemplate(''); |
2321
|
|
|
$this->viewBuilder()->setClassName('Cake\View\View'); |
2322
|
|
|
$this->viewVars = []; |
2323
|
|
|
$this->viewBuilder()->setTheme(false); |
2324
|
|
|
$this->viewBuilder()->setHelpers(['Html'], false); |
2325
|
|
|
|
2326
|
|
|
return $this; |
2327
|
|
|
} |
2328
|
|
|
|
2329
|
|
|
/** |
2330
|
|
|
* Encode the specified string using the current charset |
2331
|
|
|
* |
2332
|
|
|
* @param string $text String to encode |
2333
|
|
|
* @return string Encoded string |
2334
|
|
|
*/ |
2335
|
|
|
protected function _encode($text) |
2336
|
|
|
{ |
2337
|
|
|
$restore = mb_internal_encoding(); |
2338
|
|
|
mb_internal_encoding($this->_appCharset); |
2339
|
|
|
if (empty($this->headerCharset)) { |
2340
|
|
|
$this->headerCharset = $this->charset; |
2341
|
|
|
} |
2342
|
|
|
$return = mb_encode_mimeheader($text, $this->headerCharset, 'B'); |
2343
|
|
|
mb_internal_encoding($restore); |
2344
|
|
|
|
2345
|
|
|
return $return; |
2346
|
|
|
} |
2347
|
|
|
|
2348
|
|
|
/** |
2349
|
|
|
* Decode the specified string |
2350
|
|
|
* |
2351
|
|
|
* @param string $text String to decode |
2352
|
|
|
* @return string Decoded string |
2353
|
|
|
*/ |
2354
|
|
|
protected function _decode($text) |
2355
|
|
|
{ |
2356
|
|
|
$restore = mb_internal_encoding(); |
2357
|
|
|
mb_internal_encoding($this->_appCharset); |
2358
|
|
|
$return = mb_decode_mimeheader($text); |
2359
|
|
|
mb_internal_encoding($restore); |
2360
|
|
|
|
2361
|
|
|
return $return; |
2362
|
|
|
} |
2363
|
|
|
|
2364
|
|
|
/** |
2365
|
|
|
* Translates a string for one charset to another if the App.encoding value |
2366
|
|
|
* differs and the mb_convert_encoding function exists |
2367
|
|
|
* |
2368
|
|
|
* @param string $text The text to be converted |
2369
|
|
|
* @param string $charset the target encoding |
2370
|
|
|
* @return string |
2371
|
|
|
*/ |
2372
|
|
|
protected function _encodeString($text, $charset) |
2373
|
|
|
{ |
2374
|
|
|
if ($this->_appCharset === $charset) { |
2375
|
|
|
return $text; |
2376
|
|
|
} |
2377
|
|
|
|
2378
|
|
|
return mb_convert_encoding($text, $charset, $this->_appCharset); |
2379
|
|
|
} |
2380
|
|
|
|
2381
|
|
|
/** |
2382
|
|
|
* Wrap the message to follow the RFC 2822 - 2.1.1 |
2383
|
|
|
* |
2384
|
|
|
* @param string $message Message to wrap |
2385
|
|
|
* @param int $wrapLength The line length |
2386
|
|
|
* @return array Wrapped message |
2387
|
|
|
*/ |
2388
|
|
|
protected function _wrap($message, $wrapLength = Email::LINE_LENGTH_MUST) |
2389
|
|
|
{ |
2390
|
|
|
if (strlen($message) === 0) { |
2391
|
|
|
return ['']; |
2392
|
|
|
} |
2393
|
|
|
$message = str_replace(["\r\n", "\r"], "\n", $message); |
2394
|
|
|
$lines = explode("\n", $message); |
2395
|
|
|
$formatted = []; |
2396
|
|
|
$cut = ($wrapLength == Email::LINE_LENGTH_MUST); |
2397
|
|
|
|
2398
|
|
|
foreach ($lines as $line) { |
2399
|
|
|
if (empty($line) && $line !== '0') { |
2400
|
|
|
$formatted[] = ''; |
2401
|
|
|
continue; |
2402
|
|
|
} |
2403
|
|
|
if (strlen($line) < $wrapLength) { |
2404
|
|
|
$formatted[] = $line; |
2405
|
|
|
continue; |
2406
|
|
|
} |
2407
|
|
|
if (!preg_match('/<[a-z]+.*>/i', $line)) { |
2408
|
|
|
$formatted = array_merge( |
2409
|
|
|
$formatted, |
2410
|
|
|
explode("\n", Text::wordWrap($line, $wrapLength, "\n", $cut)) |
2411
|
|
|
); |
2412
|
|
|
continue; |
2413
|
|
|
} |
2414
|
|
|
|
2415
|
|
|
$tagOpen = false; |
2416
|
|
|
$tmpLine = $tag = ''; |
2417
|
|
|
$tmpLineLength = 0; |
2418
|
|
|
for ($i = 0, $count = strlen($line); $i < $count; $i++) { |
2419
|
|
|
$char = $line[$i]; |
2420
|
|
|
if ($tagOpen) { |
2421
|
|
|
$tag .= $char; |
2422
|
|
|
if ($char === '>') { |
2423
|
|
|
$tagLength = strlen($tag); |
2424
|
|
|
if ($tagLength + $tmpLineLength < $wrapLength) { |
2425
|
|
|
$tmpLine .= $tag; |
2426
|
|
|
$tmpLineLength += $tagLength; |
2427
|
|
|
} else { |
2428
|
|
|
if ($tmpLineLength > 0) { |
2429
|
|
|
$formatted = array_merge( |
2430
|
|
|
$formatted, |
2431
|
|
|
explode("\n", Text::wordWrap(trim($tmpLine), $wrapLength, "\n", $cut)) |
2432
|
|
|
); |
2433
|
|
|
$tmpLine = ''; |
2434
|
|
|
$tmpLineLength = 0; |
2435
|
|
|
} |
2436
|
|
|
if ($tagLength > $wrapLength) { |
2437
|
|
|
$formatted[] = $tag; |
2438
|
|
|
} else { |
2439
|
|
|
$tmpLine = $tag; |
2440
|
|
|
$tmpLineLength = $tagLength; |
2441
|
|
|
} |
2442
|
|
|
} |
2443
|
|
|
$tag = ''; |
2444
|
|
|
$tagOpen = false; |
2445
|
|
|
} |
2446
|
|
|
continue; |
2447
|
|
|
} |
2448
|
|
|
if ($char === '<') { |
2449
|
|
|
$tagOpen = true; |
2450
|
|
|
$tag = '<'; |
2451
|
|
|
continue; |
2452
|
|
|
} |
2453
|
|
|
if ($char === ' ' && $tmpLineLength >= $wrapLength) { |
2454
|
|
|
$formatted[] = $tmpLine; |
2455
|
|
|
$tmpLineLength = 0; |
2456
|
|
|
continue; |
2457
|
|
|
} |
2458
|
|
|
$tmpLine .= $char; |
2459
|
|
|
$tmpLineLength++; |
2460
|
|
|
if ($tmpLineLength === $wrapLength) { |
2461
|
|
|
$nextChar = $line[$i + 1]; |
2462
|
|
|
if ($nextChar === ' ' || $nextChar === '<') { |
2463
|
|
|
$formatted[] = trim($tmpLine); |
2464
|
|
|
$tmpLine = ''; |
2465
|
|
|
$tmpLineLength = 0; |
2466
|
|
|
if ($nextChar === ' ') { |
2467
|
|
|
$i++; |
2468
|
|
|
} |
2469
|
|
View Code Duplication |
} else { |
2470
|
|
|
$lastSpace = strrpos($tmpLine, ' '); |
2471
|
|
|
if ($lastSpace === false) { |
2472
|
|
|
continue; |
2473
|
|
|
} |
2474
|
|
|
$formatted[] = trim(substr($tmpLine, 0, $lastSpace)); |
2475
|
|
|
$tmpLine = substr($tmpLine, $lastSpace + 1); |
2476
|
|
|
|
2477
|
|
|
$tmpLineLength = strlen($tmpLine); |
2478
|
|
|
} |
2479
|
|
|
} |
2480
|
|
|
} |
2481
|
|
|
if (!empty($tmpLine)) { |
2482
|
|
|
$formatted[] = $tmpLine; |
2483
|
|
|
} |
2484
|
|
|
} |
2485
|
|
|
$formatted[] = ''; |
2486
|
|
|
|
2487
|
|
|
return $formatted; |
2488
|
|
|
} |
2489
|
|
|
|
2490
|
|
|
/** |
2491
|
|
|
* Create unique boundary identifier |
2492
|
|
|
* |
2493
|
|
|
* @return void |
2494
|
|
|
*/ |
2495
|
|
|
protected function _createBoundary() |
2496
|
|
|
{ |
2497
|
|
|
if ($this->_attachments || $this->_emailFormat === 'both') { |
|
|
|
|
2498
|
|
|
$this->_boundary = md5(Security::randomBytes(16)); |
2499
|
|
|
} |
2500
|
|
|
} |
2501
|
|
|
|
2502
|
|
|
/** |
2503
|
|
|
* Attach non-embedded files by adding file contents inside boundaries. |
2504
|
|
|
* |
2505
|
|
|
* @param string|null $boundary Boundary to use. If null, will default to $this->_boundary |
2506
|
|
|
* @return array An array of lines to add to the message |
2507
|
|
|
*/ |
2508
|
|
|
protected function _attachFiles($boundary = null) |
2509
|
|
|
{ |
2510
|
|
|
if ($boundary === null) { |
2511
|
|
|
$boundary = $this->_boundary; |
2512
|
|
|
} |
2513
|
|
|
|
2514
|
|
|
$msg = []; |
2515
|
|
|
foreach ($this->_attachments as $filename => $fileInfo) { |
2516
|
|
|
if (!empty($fileInfo['contentId'])) { |
2517
|
|
|
continue; |
2518
|
|
|
} |
2519
|
|
|
$data = isset($fileInfo['data']) ? $fileInfo['data'] : $this->_readFile($fileInfo['file']); |
2520
|
|
|
$hasDisposition = ( |
2521
|
|
|
!isset($fileInfo['contentDisposition']) || |
2522
|
|
|
$fileInfo['contentDisposition'] |
2523
|
|
|
); |
2524
|
|
|
$part = new FormDataPart('', $data, '', $this->getHeaderCharset()); |
2525
|
|
|
|
2526
|
|
|
if ($hasDisposition) { |
2527
|
|
|
$part->disposition('attachment'); |
2528
|
|
|
$part->filename($filename); |
2529
|
|
|
} |
2530
|
|
|
$part->transferEncoding('base64'); |
2531
|
|
|
$part->type($fileInfo['mimetype']); |
2532
|
|
|
|
2533
|
|
|
$msg[] = '--' . $boundary; |
2534
|
|
|
$msg[] = (string)$part; |
2535
|
|
|
$msg[] = ''; |
2536
|
|
|
} |
2537
|
|
|
|
2538
|
|
|
return $msg; |
2539
|
|
|
} |
2540
|
|
|
|
2541
|
|
|
/** |
2542
|
|
|
* Read the file contents and return a base64 version of the file contents. |
2543
|
|
|
* |
2544
|
|
|
* @param string $path The absolute path to the file to read. |
2545
|
|
|
* @return string File contents in base64 encoding |
2546
|
|
|
*/ |
2547
|
|
|
protected function _readFile($path) |
2548
|
|
|
{ |
2549
|
|
|
$File = new File($path); |
2550
|
|
|
|
2551
|
|
|
return chunk_split(base64_encode($File->read())); |
2552
|
|
|
} |
2553
|
|
|
|
2554
|
|
|
/** |
2555
|
|
|
* Attach inline/embedded files to the message. |
2556
|
|
|
* |
2557
|
|
|
* @param string|null $boundary Boundary to use. If null, will default to $this->_boundary |
2558
|
|
|
* @return array An array of lines to add to the message |
2559
|
|
|
*/ |
2560
|
|
|
protected function _attachInlineFiles($boundary = null) |
2561
|
|
|
{ |
2562
|
|
|
if ($boundary === null) { |
2563
|
|
|
$boundary = $this->_boundary; |
2564
|
|
|
} |
2565
|
|
|
|
2566
|
|
|
$msg = []; |
2567
|
|
|
foreach ($this->_attachments as $filename => $fileInfo) { |
2568
|
|
|
if (empty($fileInfo['contentId'])) { |
2569
|
|
|
continue; |
2570
|
|
|
} |
2571
|
|
|
$data = isset($fileInfo['data']) ? $fileInfo['data'] : $this->_readFile($fileInfo['file']); |
2572
|
|
|
|
2573
|
|
|
$msg[] = '--' . $boundary; |
2574
|
|
|
$part = new FormDataPart('', $data, 'inline', $this->getHeaderCharset()); |
2575
|
|
|
$part->type($fileInfo['mimetype']); |
2576
|
|
|
$part->transferEncoding('base64'); |
2577
|
|
|
$part->contentId($fileInfo['contentId']); |
2578
|
|
|
$part->filename($filename); |
2579
|
|
|
$msg[] = (string)$part; |
2580
|
|
|
$msg[] = ''; |
2581
|
|
|
} |
2582
|
|
|
|
2583
|
|
|
return $msg; |
2584
|
|
|
} |
2585
|
|
|
|
2586
|
|
|
/** |
2587
|
|
|
* Render the body of the email. |
2588
|
|
|
* |
2589
|
|
|
* @param array $content Content to render |
2590
|
|
|
* @return array Email body ready to be sent |
2591
|
|
|
*/ |
2592
|
|
|
protected function _render($content) |
2593
|
|
|
{ |
2594
|
|
|
$this->_textMessage = $this->_htmlMessage = ''; |
2595
|
|
|
|
2596
|
|
|
$content = implode("\n", $content); |
2597
|
|
|
$rendered = $this->_renderTemplates($content); |
2598
|
|
|
|
2599
|
|
|
$this->_createBoundary(); |
2600
|
|
|
$msg = []; |
2601
|
|
|
|
2602
|
|
|
$contentIds = array_filter((array)Hash::extract($this->_attachments, '{s}.contentId')); |
2603
|
|
|
$hasInlineAttachments = count($contentIds) > 0; |
2604
|
|
|
$hasAttachments = !empty($this->_attachments); |
2605
|
|
|
$hasMultipleTypes = count($rendered) > 1; |
2606
|
|
|
$multiPart = ($hasAttachments || $hasMultipleTypes); |
2607
|
|
|
|
2608
|
|
|
$boundary = $relBoundary = $textBoundary = $this->_boundary; |
2609
|
|
|
|
2610
|
|
View Code Duplication |
if ($hasInlineAttachments) { |
2611
|
|
|
$msg[] = '--' . $boundary; |
2612
|
|
|
$msg[] = 'Content-Type: multipart/related; boundary="rel-' . $boundary . '"'; |
2613
|
|
|
$msg[] = ''; |
2614
|
|
|
$relBoundary = $textBoundary = 'rel-' . $boundary; |
2615
|
|
|
} |
2616
|
|
|
|
2617
|
|
View Code Duplication |
if ($hasMultipleTypes && $hasAttachments) { |
2618
|
|
|
$msg[] = '--' . $relBoundary; |
2619
|
|
|
$msg[] = 'Content-Type: multipart/alternative; boundary="alt-' . $boundary . '"'; |
2620
|
|
|
$msg[] = ''; |
2621
|
|
|
$textBoundary = 'alt-' . $boundary; |
2622
|
|
|
} |
2623
|
|
|
|
2624
|
|
View Code Duplication |
if (isset($rendered['text'])) { |
2625
|
|
|
if ($multiPart) { |
2626
|
|
|
$msg[] = '--' . $textBoundary; |
2627
|
|
|
$msg[] = 'Content-Type: text/plain; charset=' . $this->_getContentTypeCharset(); |
2628
|
|
|
$msg[] = 'Content-Transfer-Encoding: ' . $this->_getContentTransferEncoding(); |
2629
|
|
|
$msg[] = ''; |
2630
|
|
|
} |
2631
|
|
|
$this->_textMessage = $rendered['text']; |
2632
|
|
|
$content = explode("\n", $this->_textMessage); |
2633
|
|
|
$msg = array_merge($msg, $content); |
2634
|
|
|
$msg[] = ''; |
2635
|
|
|
} |
2636
|
|
|
|
2637
|
|
View Code Duplication |
if (isset($rendered['html'])) { |
2638
|
|
|
if ($multiPart) { |
2639
|
|
|
$msg[] = '--' . $textBoundary; |
2640
|
|
|
$msg[] = 'Content-Type: text/html; charset=' . $this->_getContentTypeCharset(); |
2641
|
|
|
$msg[] = 'Content-Transfer-Encoding: ' . $this->_getContentTransferEncoding(); |
2642
|
|
|
$msg[] = ''; |
2643
|
|
|
} |
2644
|
|
|
$this->_htmlMessage = $rendered['html']; |
2645
|
|
|
$content = explode("\n", $this->_htmlMessage); |
2646
|
|
|
$msg = array_merge($msg, $content); |
2647
|
|
|
$msg[] = ''; |
2648
|
|
|
} |
2649
|
|
|
|
2650
|
|
|
if ($textBoundary !== $relBoundary) { |
2651
|
|
|
$msg[] = '--' . $textBoundary . '--'; |
2652
|
|
|
$msg[] = ''; |
2653
|
|
|
} |
2654
|
|
|
|
2655
|
|
|
if ($hasInlineAttachments) { |
2656
|
|
|
$attachments = $this->_attachInlineFiles($relBoundary); |
2657
|
|
|
$msg = array_merge($msg, $attachments); |
2658
|
|
|
$msg[] = ''; |
2659
|
|
|
$msg[] = '--' . $relBoundary . '--'; |
2660
|
|
|
$msg[] = ''; |
2661
|
|
|
} |
2662
|
|
|
|
2663
|
|
|
if ($hasAttachments) { |
2664
|
|
|
$attachments = $this->_attachFiles($boundary); |
2665
|
|
|
$msg = array_merge($msg, $attachments); |
2666
|
|
|
} |
2667
|
|
|
if ($hasAttachments || $hasMultipleTypes) { |
2668
|
|
|
$msg[] = ''; |
2669
|
|
|
$msg[] = '--' . $boundary . '--'; |
2670
|
|
|
$msg[] = ''; |
2671
|
|
|
} |
2672
|
|
|
|
2673
|
|
|
return $msg; |
2674
|
|
|
} |
2675
|
|
|
|
2676
|
|
|
/** |
2677
|
|
|
* Gets the text body types that are in this email message |
2678
|
|
|
* |
2679
|
|
|
* @return array Array of types. Valid types are 'text' and 'html' |
2680
|
|
|
*/ |
2681
|
|
|
protected function _getTypes() |
2682
|
|
|
{ |
2683
|
|
|
$types = [$this->_emailFormat]; |
2684
|
|
|
if ($this->_emailFormat === 'both') { |
2685
|
|
|
$types = ['html', 'text']; |
2686
|
|
|
} |
2687
|
|
|
|
2688
|
|
|
return $types; |
2689
|
|
|
} |
2690
|
|
|
|
2691
|
|
|
/** |
2692
|
|
|
* Build and set all the view properties needed to render the templated emails. |
2693
|
|
|
* If there is no template set, the $content will be returned in a hash |
2694
|
|
|
* of the text content types for the email. |
2695
|
|
|
* |
2696
|
|
|
* @param string $content The content passed in from send() in most cases. |
2697
|
|
|
* @return array The rendered content with html and text keys. |
2698
|
|
|
*/ |
2699
|
|
|
protected function _renderTemplates($content) |
2700
|
|
|
{ |
2701
|
|
|
$types = $this->_getTypes(); |
2702
|
|
|
$rendered = []; |
2703
|
|
|
$template = $this->viewBuilder()->getTemplate(); |
2704
|
|
|
if (empty($template)) { |
2705
|
|
|
foreach ($types as $type) { |
2706
|
|
|
$rendered[$type] = $this->_encodeString($content, $this->charset); |
2707
|
|
|
} |
2708
|
|
|
|
2709
|
|
|
return $rendered; |
2710
|
|
|
} |
2711
|
|
|
|
2712
|
|
|
$View = $this->createView(); |
2713
|
|
|
|
2714
|
|
|
list($templatePlugin) = pluginSplit($View->getTemplate()); |
2715
|
|
|
list($layoutPlugin) = pluginSplit($View->getLayout()); |
2716
|
|
|
if ($templatePlugin) { |
2717
|
|
|
$View->setPlugin($templatePlugin); |
2718
|
|
|
} elseif ($layoutPlugin) { |
2719
|
|
|
$View->setPlugin($layoutPlugin); |
2720
|
|
|
} |
2721
|
|
|
|
2722
|
|
|
if ($View->get('content') === null) { |
2723
|
|
|
$View->set('content', $content); |
2724
|
|
|
} |
2725
|
|
|
|
2726
|
|
|
foreach ($types as $type) { |
2727
|
|
|
$View->hasRendered = false; |
|
|
|
|
2728
|
|
|
$View->setTemplatePath('Email' . DIRECTORY_SEPARATOR . $type); |
2729
|
|
|
$View->setLayoutPath('Email' . DIRECTORY_SEPARATOR . $type); |
2730
|
|
|
|
2731
|
|
|
$render = $View->render(); |
2732
|
|
|
$render = str_replace(["\r\n", "\r"], "\n", $render); |
2733
|
|
|
$rendered[$type] = $this->_encodeString($render, $this->charset); |
2734
|
|
|
} |
2735
|
|
|
|
2736
|
|
|
foreach ($rendered as $type => $content) { |
2737
|
|
|
$rendered[$type] = $this->_wrap($content); |
2738
|
|
|
$rendered[$type] = implode("\n", $rendered[$type]); |
2739
|
|
|
$rendered[$type] = rtrim($rendered[$type], "\n"); |
2740
|
|
|
} |
2741
|
|
|
|
2742
|
|
|
return $rendered; |
2743
|
|
|
} |
2744
|
|
|
|
2745
|
|
|
/** |
2746
|
|
|
* Return the Content-Transfer Encoding value based |
2747
|
|
|
* on the set transferEncoding or set charset. |
2748
|
|
|
* |
2749
|
|
|
* @return string |
2750
|
|
|
*/ |
2751
|
|
|
protected function _getContentTransferEncoding() |
2752
|
|
|
{ |
2753
|
|
|
if ($this->transferEncoding) { |
2754
|
|
|
return $this->transferEncoding; |
2755
|
|
|
} |
2756
|
|
|
|
2757
|
|
|
$charset = strtoupper($this->charset); |
2758
|
|
|
if (in_array($charset, $this->_charset8bit)) { |
2759
|
|
|
return '8bit'; |
2760
|
|
|
} |
2761
|
|
|
|
2762
|
|
|
return '7bit'; |
2763
|
|
|
} |
2764
|
|
|
|
2765
|
|
|
/** |
2766
|
|
|
* Return charset value for Content-Type. |
2767
|
|
|
* |
2768
|
|
|
* Checks fallback/compatibility types which include workarounds |
2769
|
|
|
* for legacy japanese character sets. |
2770
|
|
|
* |
2771
|
|
|
* @return string |
2772
|
|
|
*/ |
2773
|
|
|
protected function _getContentTypeCharset() |
2774
|
|
|
{ |
2775
|
|
|
$charset = strtoupper($this->charset); |
2776
|
|
|
if (array_key_exists($charset, $this->_contentTypeCharset)) { |
2777
|
|
|
return strtoupper($this->_contentTypeCharset[$charset]); |
2778
|
|
|
} |
2779
|
|
|
|
2780
|
|
|
return strtoupper($this->charset); |
2781
|
|
|
} |
2782
|
|
|
|
2783
|
|
|
/** |
2784
|
|
|
* Serializes the email object to a value that can be natively serialized and re-used |
2785
|
|
|
* to clone this email instance. |
2786
|
|
|
* |
2787
|
|
|
* It has certain limitations for viewVars that are good to know: |
2788
|
|
|
* |
2789
|
|
|
* - ORM\Query executed and stored as resultset |
2790
|
|
|
* - SimpleXMLElements stored as associative array |
2791
|
|
|
* - Exceptions stored as strings |
2792
|
|
|
* - Resources, \Closure and \PDO are not supported. |
2793
|
|
|
* |
2794
|
|
|
* @return array Serializable array of configuration properties. |
2795
|
|
|
* @throws \Exception When a view var object can not be properly serialized. |
2796
|
|
|
*/ |
2797
|
|
|
public function jsonSerialize() |
2798
|
|
|
{ |
2799
|
|
|
$properties = [ |
2800
|
|
|
'_to', '_from', '_sender', '_replyTo', '_cc', '_bcc', '_subject', |
2801
|
|
|
'_returnPath', '_readReceipt', '_emailFormat', '_emailPattern', '_domain', |
2802
|
|
|
'_attachments', '_messageId', '_headers', '_appCharset', 'viewVars', 'charset', 'headerCharset', |
2803
|
|
|
]; |
2804
|
|
|
|
2805
|
|
|
$array = ['viewConfig' => $this->viewBuilder()->jsonSerialize()]; |
2806
|
|
|
|
2807
|
|
|
foreach ($properties as $property) { |
2808
|
|
|
$array[$property] = $this->{$property}; |
2809
|
|
|
} |
2810
|
|
|
|
2811
|
|
|
array_walk($array['_attachments'], function (&$item, $key) { |
2812
|
|
|
if (!empty($item['file'])) { |
2813
|
|
|
$item['data'] = $this->_readFile($item['file']); |
2814
|
|
|
unset($item['file']); |
2815
|
|
|
} |
2816
|
|
|
}); |
2817
|
|
|
|
2818
|
|
|
array_walk_recursive($array['viewVars'], [$this, '_checkViewVars']); |
2819
|
|
|
|
2820
|
|
|
return array_filter($array, function ($i) { |
2821
|
|
|
return !is_array($i) && strlen($i) || !empty($i); |
2822
|
|
|
}); |
2823
|
|
|
} |
2824
|
|
|
|
2825
|
|
|
/** |
2826
|
|
|
* Iterates through hash to clean up and normalize. |
2827
|
|
|
* |
2828
|
|
|
* @param mixed $item Reference to the view var value. |
2829
|
|
|
* @param string $key View var key. |
2830
|
|
|
* @return void |
2831
|
|
|
*/ |
2832
|
|
|
protected function _checkViewVars(&$item, $key) |
2833
|
|
|
{ |
2834
|
|
|
if ($item instanceof Exception) { |
2835
|
|
|
$item = (string)$item; |
2836
|
|
|
} |
2837
|
|
|
|
2838
|
|
|
if ( |
2839
|
|
|
is_resource($item) || |
2840
|
|
|
$item instanceof Closure || |
2841
|
|
|
$item instanceof PDO |
2842
|
|
|
) { |
2843
|
|
|
throw new RuntimeException(sprintf( |
2844
|
|
|
'Failed serializing the `%s` %s in the `%s` view var', |
2845
|
|
|
is_resource($item) ? get_resource_type($item) : get_class($item), |
2846
|
|
|
is_resource($item) ? 'resource' : 'object', |
2847
|
|
|
$key |
2848
|
|
|
)); |
2849
|
|
|
} |
2850
|
|
|
} |
2851
|
|
|
|
2852
|
|
|
/** |
2853
|
|
|
* Configures an email instance object from serialized config. |
2854
|
|
|
* |
2855
|
|
|
* @param array $config Email configuration array. |
2856
|
|
|
* @return $this Configured email instance. |
2857
|
|
|
*/ |
2858
|
|
|
public function createFromArray($config) |
2859
|
|
|
{ |
2860
|
|
|
if (isset($config['viewConfig'])) { |
2861
|
|
|
$this->viewBuilder()->createFromArray($config['viewConfig']); |
2862
|
|
|
unset($config['viewConfig']); |
2863
|
|
|
} |
2864
|
|
|
|
2865
|
|
|
foreach ($config as $property => $value) { |
2866
|
|
|
$this->{$property} = $value; |
2867
|
|
|
} |
2868
|
|
|
|
2869
|
|
|
return $this; |
2870
|
|
|
} |
2871
|
|
|
|
2872
|
|
|
/** |
2873
|
|
|
* Serializes the Email object. |
2874
|
|
|
* |
2875
|
|
|
* @return string |
2876
|
|
|
*/ |
2877
|
|
|
public function serialize() |
2878
|
|
|
{ |
2879
|
|
|
$array = $this->jsonSerialize(); |
2880
|
|
|
array_walk_recursive($array, function (&$item, $key) { |
2881
|
|
|
if ($item instanceof SimpleXMLElement) { |
2882
|
|
|
$item = json_decode(json_encode((array)$item), true); |
2883
|
|
|
} |
2884
|
|
|
}); |
2885
|
|
|
|
2886
|
|
|
return serialize($array); |
2887
|
|
|
} |
2888
|
|
|
|
2889
|
|
|
/** |
2890
|
|
|
* Unserializes the Email object. |
2891
|
|
|
* |
2892
|
|
|
* @param string $data Serialized string. |
2893
|
|
|
* @return static Configured email instance. |
2894
|
|
|
*/ |
2895
|
|
|
public function unserialize($data) |
2896
|
|
|
{ |
2897
|
|
|
return $this->createFromArray(unserialize($data)); |
2898
|
|
|
} |
2899
|
|
|
} |
2900
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.