Completed
Pull Request — master (#1087)
by Marc
02:55
created

Mail::bccAddress()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 1
nop 2
1
<?php
2
3
namespace luya\components;
4
5
use Yii;
6
use Exception;
7
use PHPMailer;
8
use SMTP;
9
10
/**
11
 * LUYA mail component to compose messages and send them via SMTP.
12
 *
13
 * This component is registered on each LUYA instance, how to use:
14
 *
15
 * ```php
16
 * if (Yii::$app->mail->compose('Subject', 'Message body of the Mail'->adress('[email protected]')->send()) {
17
 *     echo "Mail has been sent!";
18
 * } else {
19
 *     echo "Error" : Yii::$app->mail->error;
20
 * }
21
 * ```
22
 *
23
 * SMTP debug help:
24
 *
25
 * ```
26
 * swaks -s HOST -p 587 -ehlo localhost -au AUTH_USER -to TO_ADRESSE -tls
27
 * ```
28
 *
29
 * @property \PHPMailer $mailer The PHP Mailer object
30
 *
31
 * @author Basil Suter <[email protected]>
32
 */
33
class Mail extends \yii\base\Component
34
{
35
    private $_mailer = null;
36
37
    /**
38
     * @var string sender email address
39
     */
40
    public $from = '[email protected]';
41
42
    /**
43
     * @var string sender name
44
     */
45
    public $fromName = '[email protected]';
46
47
    /**
48
     * @var string email server host address
49
     */
50
    public $host = 'mail.zephir.ch';
51
52
    /**
53
     * @var string email server username
54
     */
55
    public $username = '[email protected]';
56
57
    /**
58
     * @var string email server password
59
     */
60
    public $password = null; // insert password
61
62
    /**
63
     * @var bool disable if you want to use old PHP sendmail
64
     */
65
    public $isSMTP = true;
66
67
    /**
68
     * @var string alternate text message if email client doesn't support HTML
69
     */
70
    public $altBody = 'Please use a HTML compatible E-Mail-Client to read this E-Mail.';
71
72
    /**
73
     * @var int email server port
74
     */
75
    public $port = 587;
76
77
    /**
78
     * @var bool enable debug output mode 'Data and commands'
79
     */
80
    public $debug = false;
81
    
82
    /**
83
     * @var string Posible values are `tls` or `ssl`
84
     */
85
    public $smtpSecure = 'tls';
86
    
87
    /**
88
     * @since 1.0.0-beta7
89
     * @var string|boolean Define a layout template file which is going to be wrapped around the setBody()
90
     * content. The file alias will be resolved so an example layout could look as followed:
91
     *
92
     * ```php
93
     * $layout = '@app/views/maillayout.php';
94
     * ```
95
     *
96
     * In your config or any mailer object. As in layouts the content of the mail specific html can be access
97
     * in the `$content` variable. The example content of `maillayout.php` from above could look like this:
98
     *
99
     * ```php
100
     * <h1>My Company</h1>
101
     * <div><?= $content; ?></div>
102
     * ```
103
     */
104
    public $layout = false;
105
    
106
    /**
107
     * Getter for the mailer object
108
     *
109
     * @return \PHPMailer
110
     */
111
    public function getMailer()
112
    {
113
        if ($this->_mailer === null) {
114
            $this->_mailer = new PHPmailer;
115
            $this->_mailer->CharSet = 'UTF-8';
116
            $this->_mailer->From = $this->from;
117
            $this->_mailer->FromName = $this->fromName;
118
            $this->_mailer->isHTML(true);
119
            $this->_mailer->AltBody = $this->altBody;
120
            // if sending over smtp, define the settings for the smpt server
121
            if ($this->isSMTP) {
122
                if ($this->debug) {
123
                    $this->_mailer->SMTPDebug = 2;
124
                }
125
                $this->_mailer->isSMTP();
126
                $this->_mailer->SMTPSecure = $this->smtpSecure;
127
                $this->_mailer->Host = $this->host;
128
                $this->_mailer->SMTPAuth = true;
129
                $this->_mailer->Username = $this->username;
130
                $this->_mailer->Password = $this->password;
131
                $this->_mailer->Port = $this->port;
132
                $this->_mailer->SMTPOptions = [
133
                    'ssl' => ['verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true],
134
                ];
135
            }
136
        }
137
138
        return $this->_mailer;
139
    }
140
    
141
    /**
142
     * Reset the mailer object to null
143
     *
144
     * @return void
145
     */
146
    public function cleanup()
147
    {
148
        $this->_mailer = null;
149
    }
150
    
151
    /**
152
     * Compose a new mail message, this will first flush existing mailer objects
153
     *
154
     * @param string $subject The subject of the mail
155
     * @param string $body The HTML body of the mail message.
156
     * @return \luya\components\Mail
157
     */
158
    public function compose($subject, $body)
159
    {
160
        $this->cleanup();
161
        $this->setSubject($subject);
162
        $this->setBody($body);
163
        return $this;
164
    }
165
    
166
    /**
167
     * Set the mail message subject of the mailer instance
168
     *
169
     * @param string $subject The subject message
170
     * @return \luya\components\Mail
171
     */
172
    public function setSubject($subject)
173
    {
174
        $this->getMailer()->Subject = $subject;
175
        return $this;
176
    }
177
    
178
    /**
179
     * Set the HTML body for the mailer message, if a layout is defined the layout
180
     * will automatically wrapped about the html body.
181
     *
182
     * @param string $body The HTML body message
183
     * @return \luya\components\Mail
184
     */
185
    public function setBody($body)
186
    {
187
        $this->getMailer()->Body = $this->wrapLayout($body);
188
        return $this;
189
    }
190
191
    /**
192
     * Wrap the layout from the `$layout` propertie and store
193
     * the passed  content as $content variable in the view.
194
     *
195
     * @param string $content The content to wrapp inside the layout.
196
     */
197
    protected function wrapLayout($content)
198
    {
199
        // do not wrap the content if layout is turned off.
200
        if ($this->layout === false) {
201
            return $content;
202
        }
203
        
204
        $view = Yii::$app->getView();
205
        return $view->renderPhpFile(Yii::getAlias($this->layout), ['content' => $content]);
0 ignored issues
show
Bug introduced by
It seems like $this->layout can also be of type boolean; however, yii\BaseYii::getAlias() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
206
    }
207
    
208
    /**
209
     * Add multiple addresses into the mailer object.
210
     *
211
     * If no key is used, the name is going to be ignored, if a string key is available it represents the name.
212
     *
213
     * ```php
214
     * adresses(['[email protected]', '[email protected]']);
215
     * ```
216
     *
217
     * or with names
218
     *
219
     * ```php
220
     * adresses(['John Doe' => '[email protected]', 'Jane Doe' => '[email protected]']);
221
     * ```
222
     *
223
     * @return \luya\components\Mail
224
     * @since 1.0.0-beta4
225
     * @param array $emails An array with email adresses or name => email paring to use names.
226
     */
227
    public function adresses(array $emails)
228
    {
229
        foreach ($emails as $name => $mail) {
230
            if (is_int($name)) {
231
                $this->address($mail);
232
            } else {
233
                $this->address($mail, $name);
234
            }
235
        }
236
        
237
        return $this;
238
    }
239
    
240
    /**
241
     * Correct spelled alias method for `adresses`.
242
     *
243
     * @todo remove wrong spelled on release
244
     * @param array $emails
245
     * @return \luya\components\Mail
246
     */
247
    public function addresses(array $emails)
248
    {
249
        return $this->adresses($emails);
250
    }
251
    
252
    /**
253
     * Add a single address with optional name
254
     *
255
     * @param string $email The email address e.g. [email protected]
256
     * @param string $name The name for the address e.g. John Doe
257
     * @return \luya\components\Mail
258
     */
259
    public function address($email, $name = null)
260
    {
261
        $this->getMailer()->addAddress($email, (empty($name)) ? $email : $name);
262
263
        return $this;
264
    }
265
266
    /**
267
     * Add multiple CC addresses into the mailer object.
268
     *
269
     * If no key is used, the name is going to be ignored, if a string key is available it represents the name.
270
     *
271
     * ```php
272
     * ccAddresses(['[email protected]', '[email protected]']);
273
     * ```
274
     *
275
     * or with names
276
     *
277
     * ```php
278
     * ccAddresses(['John Doe' => '[email protected]', 'Jane Doe' => '[email protected]']);
279
     * ```
280
     *
281
     * @return \luya\components\Mail
282
     * @since 1.0.0-RC2
283
     * @param array $emails An array with email addresses or name => email paring to use names.
284
     */
285
    public function ccAddresses(array $emails)
286
    {
287
        foreach ($emails as $name => $mail) {
288
            if (is_int($name)) {
289
                $this->ccAddress($mail);
290
            } else {
291
                $this->ccAddress($mail, $name);
292
            }
293
        }
294
295
        return $this;
296
    }
297
298
    /**
299
     * Add a single CC address with optional name
300
     *
301
     * @param string $email The email address e.g. [email protected]
302
     * @param string $name The name for the address e.g. John Doe
303
     * @return \luya\components\Mail
304
     */
305
    public function ccAddress($email, $name = null)
306
    {
307
        $this->getMailer()->addCC($email, (empty($name)) ? $email : $name);
308
309
        return $this;
310
    }
311
312
    /**
313
     * Add multiple BCC addresses into the mailer object.
314
     *
315
     * If no key is used, the name is going to be ignored, if a string key is available it represents the name.
316
     *
317
     * ```php
318
     * bccAddresses(['[email protected]', '[email protected]']);
319
     * ```
320
     *
321
     * or with names
322
     *
323
     * ```php
324
     * bccAddresses(['John Doe' => '[email protected]', 'Jane Doe' => '[email protected]']);
325
     * ```
326
     *
327
     * @return \luya\components\Mail
328
     * @since 1.0.0-RC2
329
     * @param array $emails An array with email addresses or name => email paring to use names.
330
     */
331
    public function bccAddresses(array $emails)
332
    {
333
        foreach ($emails as $name => $mail) {
334
            if (is_int($name)) {
335
                $this->bccAddress($mail);
336
            } else {
337
                $this->bccAddress($mail, $name);
338
            }
339
        }
340
341
        return $this;
342
    }
343
344
    /**
345
     * Add a single BCC address with optional name
346
     *
347
     * @param string $email The email address e.g. [email protected]
348
     * @param string $name The name for the address e.g. John Doe
349
     * @return \luya\components\Mail
350
     */
351
    public function bccAddress($email, $name = null)
352
    {
353
        $this->getMailer()->addBCC($email, (empty($name)) ? $email : $name);
354
355
        return $this;
356
    }
357
358
    /**
359
     * Trigger the send event of the mailer
360
     *
361
     * @return boolean
362
     */
363
    public function send()
364
    {
365
        return $this->getMailer()->send();
366
    }
367
368
    /**
369
     * Get the mailer error info if any.
370
     *
371
     * @return string
372
     */
373
    public function getError()
374
    {
375
        return $this->getMailer()->ErrorInfo;
376
    }
377
378
    /**
379
     * @see https://github.com/PHPMailer/PHPMailer/blob/master/examples/smtp_check.phps
380
     *
381
     * @throws Exception
382
     */
383
    public function smtpTest($verbose)
384
    {
385
        //Create a new SMTP instance
386
        $smtp = new SMTP();
387
        
388
        if ($verbose) {
389
            // Enable connection-level debug output
390
            $smtp->do_debug = 3;
391
        }
392
        
393
        try {
394
            // connect to an SMTP server
395
            if ($smtp->connect($this->host, $this->port)) {
396
                // yay hello
397
                if ($smtp->hello('localhost')) {
398
                    if ($smtp->authenticate($this->username, $this->password)) {
399
                        return true;
400
                    } else {
401
                        $data = [$this->host, $this->port, $this->smtpSecure, $this->username];
402
                        throw new Exception('Authentication failed ('.implode(',', $data).'): '.$smtp->getLastReply() . PHP_EOL . print_r($smtp->getError(), true));
403
                    }
404
                } else {
405
                    throw new Exception('HELO failed: '.$smtp->getLastReply());
406
                }
407
            } else {
408
                throw new Exception('Connect failed');
409
            }
410
        } catch (Exception $e) {
411
            $smtp->quit(true);
412
            throw new \yii\base\Exception($e->getMessage());
413
        }
414
    }
415
}
416