├── .gitignore ├── example ├── images │ └── mail │ │ └── yii.png ├── files │ └── yii-1.1.0-validator-cheatsheet.pdf └── protected │ ├── views │ ├── mail │ │ ├── contact.php │ │ └── cron.php │ ├── layouts │ │ └── mail.php │ └── site │ │ └── contact.php │ ├── config │ ├── console.php │ ├── mail.php │ └── main.php │ ├── yiic.php │ ├── commands │ └── CronCommand.php │ └── controllers │ └── SiteController.php ├── composer.json ├── README.md └── src └── YiiMailer.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor -------------------------------------------------------------------------------- /example/images/mail/yii.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vernes/YiiMailer/HEAD/example/images/mail/yii.png -------------------------------------------------------------------------------- /example/files/yii-1.1.0-validator-cheatsheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vernes/YiiMailer/HEAD/example/files/yii-1.1.0-validator-cheatsheet.pdf -------------------------------------------------------------------------------- /example/protected/views/mail/contact.php: -------------------------------------------------------------------------------- 1 |
Message from
2 | 3 |You may change the content of this page by modifying the following two files:
4 |Message from
2 | 3 |You may change the content of this page by modifying the following two files:
4 || 10 | name); ?> 11 | | 12 |
| 15 | 16 | | 17 |
| 20 | 21 | | 22 |
25 |
26 | |
27 |
25 | If you have business inquiries or other questions, please fill out the following form to contact us. Thank you. 26 |
27 | 28 |Fields with * are required.
39 | 40 | errorSummary($model); ?> 41 | 42 |
27 | Yii::setPathOfAlias('webroot.images.mail', '/path/to/your/images/mail/dir');
28 |
29 |
30 | Yet another solution is to override protected/yiic.php and set 'webroot' alias there (see example files).
31 |
32 | ## Usage
33 |
34 | Instantiate YiiMailer in your controller or console command and pass view and data array:
35 |
36 | $mail = new YiiMailer('contact', array('message' => 'Message to send', 'name' => 'John Doe', 'description' => 'Contact form'));
37 |
38 | or
39 |
40 | $mail = new YiiMailer();
41 | $mail->setView('contact');
42 | $mail->setData(array('message' => 'Message to send', 'name' => 'John Doe', 'description' => 'Contact form'));
43 |
44 | Layout is automatically set from config but you may override it with
45 |
46 | $mail->setLayout('layoutName');
47 |
48 |
49 | Set the properties:
50 |
51 | $mail->setFrom('from@example.com', 'John Doe');
52 | $mail->setTo(Yii::app()->params['adminEmail']);
53 | $mail->setSubject('Mail subject');
54 |
55 | You may use all PHPMailer properties you would usually use.
56 |
57 | And finally send email(s):
58 |
59 | if ($mail->send()) {
60 | Yii::app()->user->setFlash('contact','Thank you for contacting us. We will respond to you as soon as possible.');
61 | } else {
62 | Yii::app()->user->setFlash('error','Error while sending email: '.$mail->getError());
63 | }
64 |
65 |
66 | ### Sending simple messages
67 |
68 | You can send email without both the layout and view by using:
69 |
70 | $mail = new YiiMailer();
71 | //$mail->clearLayout();//if layout is already set in config
72 | $mail->setFrom('from@example.com', 'John Doe');
73 | $mail->setTo(Yii::app()->params['adminEmail']);
74 | $mail->setSubject('Mail subject');
75 | $mail->setBody('Simple message');
76 | $mail->send();
77 |
78 |
79 | Alternatively, you may also send email message with layout but without specific view (set layout and set body) or with view but without layout (clear layout and set view).
80 |
81 | ### Setting addresses
82 |
83 | When using methods for setting addresses (setTo(), setCc(), setBcc(), setReplyTo()) any of the following is valid for arguments:
84 |
85 | $mail->setTo('john@example.com');
86 | $mail->setTo(array('john@example.com','jane@example.com'));
87 | $mail->setTo(array('john@example.com'=>'John Doe','jane@example.com'));
88 |
89 |
90 | ### Sending attachments
91 |
92 | You may send one or more attachments using setAttachemnt() method:
93 |
94 | $mail->setAttachment('something.pdf');
95 | $mail->setAttachment(array('something.pdf','something_else.pdf','another.doc'));
96 | $mail->setAttachment(array('something.pdf'=>'Some file','something_else.pdf'=>'Another file'));
97 |
98 |
99 | ### Test mode
100 |
101 | When working locally without mail server installed, it may be useful to save emails as files instead of trying to send them and getting errors in the process.
102 | To use test mode, you must specify path to directory where you want to save your emails and set 'testMode' property to 'true' in your config:
103 |
104 | 105 | 'savePath' => 'webroot.assets.mail', 106 | 'testMode' => true, 107 |108 | 109 | Emails are saved as .eml files and you can use software like Mozilla Thunderbird to open them. 110 | 111 | 112 | ### Using SMTP 113 | 114 | If you want to use SMTP, configure appropriate properties in your config. 115 | Example setup for GMail: 116 |
117 | 'Mailer' => 'smtp', 118 | 'Host' => 'smtp.gmail.com', 119 | 'Port' => 465, 120 | 'SMTPSecure' => 'ssl', 121 | 'SMTPAuth' => true, 122 | 'Username' => 'your_email@gmail.com', 123 | 'Password' => 'your_password', 124 |125 | 126 | You may also configure this just before sending email: 127 |
128 | $mail->setSmtp('smtp.gmail.com', 465, 'ssl', true, 'your_email@gmail.com', 'your_password');
129 |
130 |
131 | ## Examples
132 |
133 | Two examples included: one for standard contact form in yii web app and the other one for yii console app.
134 |
--------------------------------------------------------------------------------
/src/YiiMailer.php:
--------------------------------------------------------------------------------
1 | params[self::CONFIG_PARAMS]))
81 | $config = Yii::app()->params[self::CONFIG_PARAMS];
82 | else
83 | $config = require(Yii::getPathOfAlias('application.config') . DIRECTORY_SEPARATOR . self::CONFIG_FILE);
84 | //set config
85 | $this->setConfig($config);
86 | //set view
87 | $this->setView($view);
88 | //set data
89 | $this->setData($data);
90 | //set layout
91 | $this->setLayout($layout);
92 | }
93 |
94 | /**
95 | * Configure parameters
96 | * @param array $config Config parameters
97 | * @throws CException
98 | */
99 | private function setConfig($config)
100 | {
101 | if (!is_array($config))
102 | throw new CException("Configuration options must be an array!");
103 | foreach ($config as $key => $val) {
104 | $this->$key = $val;
105 | }
106 | }
107 |
108 | /**
109 | * Set the view to be used
110 | * @param string $view View file
111 | * @param string $type The view type: 'HTML' or 'Text'
112 | * @throws CException
113 | */
114 | public function setView($view, $type = "HTML")
115 | {
116 | if (!empty($view)) {
117 | if (!is_file($this->getViewFile($this->viewPath . '.' . $view)))
118 | throw new CException('View "' . $view . '" not found');
119 |
120 | switch ($type) {
121 | case "HTML":
122 | $this->view = $view;
123 | break;
124 | case "Text":
125 | $this->textView = $view;
126 | }
127 | }
128 | }
129 |
130 | /**
131 | * Get currently used view
132 | * @return string HTML View filename
133 | */
134 | public function getView()
135 | {
136 | return $this->view;
137 | }
138 |
139 | /**
140 | * Set the HTML view to be used
141 | * @param string $view HTML View file
142 | */
143 | public function setHTMLView($view)
144 | {
145 | $this->setView($view, "HTML");
146 | }
147 |
148 | /**
149 | * Set the Text view to be used
150 | * @param string $view Text View file
151 | */
152 | public function setTextView($view)
153 | {
154 | $this->setView($view, "Text");
155 | }
156 |
157 | /**
158 | * Get currently used text view
159 | * @return string Text View filename
160 | */
161 | public function getTextView()
162 | {
163 | $this->textView;
164 | }
165 |
166 | /**
167 | * Clear currently used view
168 | */
169 | public function clearView()
170 | {
171 | $this->view = null;
172 | }
173 |
174 | /**
175 | * Set the alt body text to be applied to $AltBody
176 | * @param string $text
177 | */
178 | public function setAltText($text = '')
179 | {
180 | $this->altText = $text;
181 | }
182 |
183 | /**
184 | * Get the alt body text to be applied to $AltBody
185 | * @return string the text to be applied to $altBody
186 | */
187 | public function getAltText()
188 | {
189 | $this->altText;
190 | }
191 |
192 | /**
193 | * Send data to be used in mail body
194 | * @param array $data Data array
195 | */
196 | public function setData($data)
197 | {
198 | $this->data = $data;
199 | }
200 |
201 | /**
202 | * Get current data array
203 | * @return array Data array
204 | */
205 | public function getData()
206 | {
207 | return $this->data;
208 | }
209 |
210 | /**
211 | * Clear current data array
212 | */
213 | public function clearData()
214 | {
215 | $this->data = array();
216 | }
217 |
218 | /**
219 | * Set layout file to be used
220 | * @param string $layout Layout filename
221 | * @throws CException
222 | */
223 | public function setLayout($layout)
224 | {
225 | if ($layout != '') {
226 | if (!is_file($this->getViewFile($this->layoutPath . '.' . $layout)))
227 | throw new CException('Layout "' . $layout . '" not found!');
228 | $this->layout = $layout;
229 | }
230 | }
231 |
232 | /**
233 | * Get current layout
234 | * @return string Layout filename
235 | */
236 | public function getLayout()
237 | {
238 | return $this->layout;
239 | }
240 |
241 | /**
242 | * Clear current layout
243 | */
244 | public function clearLayout()
245 | {
246 | $this->layout = null;
247 | }
248 |
249 | /**
250 | * Set path for email views
251 | * @param string $path Yii path
252 | * @throws CException
253 | */
254 | public function setViewPath($path)
255 | {
256 | if (!is_string($path) && !preg_match("/[a-z0-9\.]/i", $path))
257 | throw new CException('Path "' . $path . '" not valid!');
258 | $this->viewPath = $path;
259 | }
260 |
261 | /**
262 | * Get path for email views
263 | * @return string Yii path
264 | */
265 | public function getViewPath()
266 | {
267 | return $this->viewPath;
268 | }
269 |
270 | /**
271 | * Set path for email layouts
272 | * @param string $path Yii path
273 | * @throws CException
274 | */
275 | public function setLayoutPath($path)
276 | {
277 | if (!is_string($path) && !preg_match("/[a-z0-9\.]/i", $path))
278 | throw new CException('Path "' . $path . '" not valid!');
279 | $this->layoutPath = $path;
280 | }
281 |
282 | /**
283 | * Get path for email layouts
284 | * @return string Yii path
285 | */
286 | public function getLayoutPath()
287 | {
288 | return $this->layoutPath;
289 | }
290 |
291 | /**
292 | * Set path for images to embed in email messages
293 | * @param string $path Yii path
294 | * @throws CException
295 | */
296 | public function setBaseDirPath($path)
297 | {
298 | if (!is_string($path) && !preg_match("/[a-z0-9\.]/i", $path))
299 | throw new CException('Path "' . $path . '" not valid!');
300 | $this->baseDirPath = $path;
301 | }
302 |
303 | /**
304 | * Get path for email images
305 | * @return string Yii path
306 | */
307 | public function getBaseDirPath()
308 | {
309 | return $this->baseDirPath;
310 | }
311 |
312 | /**
313 | * Set From address and name
314 | * @param string $address Email address of the sender
315 | * @param string $name Name of the sender
316 | * @param boolean $auto Also set the Reply-To
317 | * @return boolean True on success, false if address not valid
318 | */
319 | public function setFrom($address, $name = '', $auto = true)
320 | {
321 | return parent::setFrom($address, $name, (bool)$auto);
322 | }
323 |
324 | /**
325 | * Set one or more email addresses to send to
326 | * Valid arguments:
327 | * $mail->setTo('john@example.com');
328 | * $mail->setTo(array('john@example.com','jane@example.com'));
329 | * $mail->setTo(array('john@example.com'=>'John Doe','jane@example.com'));
330 | * @param mixed $addresses Email address or array of email addresses
331 | * @return boolean True on success, false if addresses not valid
332 | */
333 | public function setTo($addresses)
334 | {
335 | $this->clearAddresses();
336 | return $this->setAddresses('to', $addresses);
337 | }
338 |
339 | /**
340 | * Set one or more CC email addresses
341 | * @param mixed $addresses Email address or array of email addresses
342 | * @return boolean True on success, false if addresses not valid
343 | */
344 | public function setCc($addresses)
345 | {
346 | $this->clearCCs();
347 | return $this->setAddresses('cc', $addresses);
348 | }
349 |
350 | /**
351 | * Set one or more BCC email addresses
352 | * @param mixed $addresses Email address or array of email addresses
353 | * @return boolean True on success, false if addresses not valid
354 | */
355 | public function setBcc($addresses)
356 | {
357 | $this->clearBCCs();
358 | return $this->setAddresses('bcc', $addresses);
359 | }
360 |
361 | /**
362 | * Set one or more Reply-To email addresses
363 | * @param mixed $addresses Email address or array of email addresses
364 | * @return boolean True on success, false if addresses not valid
365 | */
366 | public function setReplyTo($addresses)
367 | {
368 | $this->clearReplyTos();
369 | return $this->setAddresses('Reply-To', $addresses);
370 | }
371 |
372 | /**
373 | * Set one or more email addresses of different kinds
374 | * @param string $type Type of the recipient (to, cc, bcc or Reply-To)
375 | * @param mixed $addresses Email address or array of email addresses
376 | * @return boolean True on success, false if addresses not valid
377 | */
378 | private function setAddresses($type, $addresses)
379 | {
380 | if (!is_array($addresses)) {
381 | $addresses = (array)$addresses;
382 | }
383 |
384 | $result = true;
385 | foreach ($addresses as $key => $value) {
386 | if (is_int($key))
387 | $r = $this->addAnAddress($type, $value);
388 | else
389 | $r = $this->addAnAddress($type, $key, $value);
390 | if ($result && !$r)
391 | $result = false;
392 | }
393 |
394 | return $result;
395 | }
396 |
397 | /**
398 | * Set subject of the email
399 | * @param string $subject Subject of the email
400 | */
401 | public function setSubject($subject)
402 | {
403 | $this->Subject = $subject;
404 | }
405 |
406 | /**
407 | * Set text body of the email
408 | * @param string $body Textual body of the email
409 | */
410 | public function setBody($body)
411 | {
412 | $this->Body = $body;
413 | }
414 |
415 | /**
416 | * Set one or more email attachments
417 | * Valid arguments:
418 | * $mail->setAttachment('something.pdf');
419 | * $mail->setAttachment(array('something.pdf','something_else.pdf','another.doc'));
420 | * $mail->setAttachment(array('something.pdf'=>'Some file','something_else.pdf'=>'Another file'));
421 | * @param mixed $attachments Path to the file or array of files to attach
422 | * @return boolean True on success, false if addresses not valid
423 | */
424 | public function setAttachment($attachments)
425 | {
426 | if (!is_array($attachments))
427 | $attachments = (array)$attachments;
428 |
429 | $result = true;
430 | foreach ($attachments as $key => $value) {
431 | if (is_int($key))
432 | $r = $this->addAttachment($value);
433 | else
434 | $r = $this->addAttachment($key, $value);
435 | if ($result && !$r)
436 | $result = false;
437 | }
438 |
439 | return $result;
440 | }
441 |
442 | /**
443 | * Clear all recipients and attachments
444 | */
445 | public function clear()
446 | {
447 | $this->clearAllRecipients();
448 | $this->clearReplyTos();
449 | $this->clearAttachments();
450 | }
451 |
452 | /**
453 | * Get current error message
454 | * @return string Error message
455 | */
456 | public function getError()
457 | {
458 | return $this->ErrorInfo;
459 | }
460 |
461 | /**
462 | * Find the view file for the given view name
463 | * @param string $viewName Name of the view
464 | * @return string The file path or false if the file does not exist
465 | */
466 | public function getViewFile($viewName)
467 | {
468 | //In web application, use existing method
469 | if (isset(Yii::app()->controller))
470 | return Yii::app()->controller->getViewFile($viewName);
471 | //resolve the view file
472 | //TODO: support for themes in console applications
473 | if (empty($viewName))
474 | return false;
475 |
476 | $viewFile = Yii::getPathOfAlias($viewName);
477 | if (is_file($viewFile . '.php'))
478 | return Yii::app()->findLocalizedFile($viewFile . '.php');
479 | else
480 | return false;
481 | }
482 |
483 | /**
484 | * Render the view file
485 | * @param string $viewName Name of the view
486 | * @param array $viewData Data for extraction
487 | * @return string The rendered result
488 | * @throws CException
489 | */
490 | public function renderView($viewName, $viewData = null)
491 | {
492 | //resolve the file name
493 | if (($viewFile = $this->getViewFile($viewName)) !== false) {
494 | //use controller instance if available or create dummy controller for console applications
495 | if (isset(Yii::app()->controller))
496 | return Yii::app()->controller->renderFile($viewFile, $viewData, true);
497 | else {
498 | $controller = new CController(__CLASS__);
499 | return $controller->renderInternal($viewFile, $viewData, true);
500 | }
501 | } else {
502 | //file name does not exist
503 | throw new CException('View "' . $viewName . '" does not exist!');
504 | }
505 |
506 | }
507 |
508 | /**
509 | * Generates HTML email, with or without layout
510 | */
511 | public function render()
512 | {
513 | //render view as body if specified
514 | if (isset($this->view))
515 | $this->setBody($this->renderView($this->viewPath . '.' . $this->view, $this->data));
516 |
517 | //render with layout if given
518 | if ($this->layout) {
519 | //has layout
520 | $this->MsgHTMLWithLayout($this->Body, Yii::getPathOfAlias($this->baseDirPath));
521 | } else {
522 | //no layout
523 | $this->MsgHTML($this->Body, Yii::getPathOfAlias($this->baseDirPath));
524 | }
525 |
526 | //render alt body if specified
527 | if (isset($this->textView)) {
528 | $this->AltBody = $this->renderView($this->viewPath . '.' . $this->textView, $this->data);
529 | } elseif (isset($this->altText)) {
530 | $this->AltBody = $this->altText;
531 | }
532 | }
533 |
534 | /**
535 | * Render HTML email message with layout
536 | * @param string $message Email message
537 | * @param string $basedir Path for images to embed in message
538 | */
539 | protected function MsgHTMLWithLayout($message, $basedir = '')
540 | {
541 | $this->msgHTML($this->renderView($this->layoutPath . '.' . $this->layout, array('content' => $message, 'data' => $this->data)), $basedir);
542 | }
543 |
544 | /**
545 | * Render message and send emails
546 | * @return boolean True if sent successfully, false otherwise
547 | */
548 | public function send()
549 | {
550 | //render message
551 | $this->render();
552 |
553 | //send the message
554 | try {
555 | //prepare the message
556 | if (!$this->preSend())
557 | return false;
558 |
559 | //in test mode, save message as a file
560 | if ($this->testMode)
561 | return $this->save();
562 | else
563 | return $this->postSend();
564 | } catch (Exception $e) {
565 | $this->mailHeader = '';
566 | $this->setError($e->getMessage());
567 | if ($this->exceptions) {
568 | throw $e;
569 | }
570 | return false;
571 | }
572 | }
573 |
574 | /**
575 | * Save message as eml file
576 | * @return boolean True if saved successfully, false otherwise
577 | */
578 | public function save()
579 | {
580 | $filename = date('YmdHis') . (!empty($this->view) ? '_' . $this->view : '') . '_' . uniqid() . '.eml';
581 | $dir = Yii::getPathOfAlias($this->savePath);
582 |
583 | // Create a directory
584 | if (!is_dir($dir)) {
585 | $oldmask = @umask(0);
586 | $result = @mkdir($dir, 0777);
587 | @umask($oldmask);
588 | if (!$result) {
589 | throw new CException('Unable to create the directory ' . $dir);
590 | }
591 | }
592 |
593 | try {
594 | $file = fopen($dir . DIRECTORY_SEPARATOR . $filename, 'w+');
595 | fwrite($file, $this->getSentMIMEMessage());
596 | fclose($file);
597 |
598 | return true;
599 | } catch (Exception $e) {
600 | $this->setError($e->getMessage());
601 |
602 | return false;
603 | }
604 | }
605 |
606 | /**
607 | * Setup SMTP and use it to send email
608 | * @param string $host SMTP hosts, either a single hostname or multiple semicolon-delimited hostnames
609 | * @param int $port The default SMTP server port
610 | * @param string $secure The secure connection prefix. Options: "", "ssl" or "tls"
611 | * @param boolean $auth Whether to use SMTP authentication
612 | * @param string $username SMTP username
613 | * @param string $password SMTP password
614 | */
615 | public function setSmtp($host = 'localhost', $port = 25, $secure = '', $auth = false, $username = '', $password = '')
616 | {
617 | $this->isSMTP();
618 | $this->Host = $host;
619 | $this->Port = $port;
620 | $this->SMTPSecure = $secure;
621 | $this->SMTPAuth = $auth;
622 | $this->Username = $username;
623 | $this->Password = $password;
624 | }
625 | }
626 |
--------------------------------------------------------------------------------