| 7 | | Email sending is handled by the `sfMail` class. It is a proxy class that offers an interface with [PhpMailer](http://phpmailer.sourceforge.net/). |
|---|
| 8 | | |
|---|
| 9 | | This proxy class allows you to define your own interface if required. |
|---|
| 10 | | |
|---|
| 11 | | Example |
|---|
| 12 | | ------- |
|---|
| 13 | | |
|---|
| 14 | | [php] |
|---|
| 15 | | require_once 'sf/sfMail.class.php'; |
|---|
| 16 | | |
|---|
| 17 | | // class initialization |
|---|
| 18 | | $mail = sfMail::newInstance('PhpMailer'); |
|---|
| 19 | | $mail->initialize(); |
|---|
| 20 | | $mail->setMailer('sendmail'); |
|---|
| 21 | | |
|---|
| 22 | | // definition of the required parameters |
|---|
| 23 | | $mail->addAddress('client@client.com'); |
|---|
| 24 | | $mail->setSender('me@symfony-project.com', 'Symfony'); |
|---|
| | 12 | Symfony offers two ways to send emails from your web application: |
|---|
| | 13 | |
|---|
| | 14 | - Via the `sfMail` class, which is a proxy class that offers an interface with [PHPMailer](http://phpmailer.sourceforge.net/). This solution is simple and fast, but doesn't provide MVC separation and is hardly compatible with i18n. Complex emails are also harder to compose with the `sfMail` class alone. |
|---|
| | 15 | |
|---|
| | 16 | - Via a specific action and template. This solution is very versatile and deals with emails just as regular pages, with the addition of the specificities of this media. It is a little longer to put in place, but much more powerful than the first one. |
|---|
| | 17 | |
|---|
| | 18 | The implementation of both solution will be illustrated through the same example: the sending of a forgotten password requested by a user. |
|---|
| | 19 | |
|---|
| | 20 | Direct use of `sfMail` |
|---|
| | 21 | ---------------------- |
|---|
| | 22 | |
|---|
| | 23 | The `sfMail` class will look familiar to those who know the `PHPMailer` class. It is simply a proxy class to `PHPMailer`, taking advantage of the symfony syntax. The `PHPMailer` class is included in the symfony package, so no additional installation is required. |
|---|
| | 24 | |
|---|
| | 25 | To send an email containing a password to a customer, an action has to do like the following: |
|---|
| | 26 | |
|---|
| | 27 | [php] |
|---|
| | 28 | public function executePasswordRequest() |
|---|
| | 29 | { |
|---|
| | 30 | // determine customer from the request 'id' parameter |
|---|
| | 31 | $customer = CustomerPeer::retrieveByPk($this->getRequestParameter('id')); |
|---|
| | 32 | |
|---|
| | 33 | require_once 'sf/sfMail.class.php'; |
|---|
| | 34 | |
|---|
| | 35 | // class initialization |
|---|
| | 36 | $mail = new sfMail(); |
|---|
| | 37 | $mail->initialize(); |
|---|
| | 38 | $mail->setMailer('sendmail'); |
|---|
| | 39 | $mail->setCharset('utf-8'); |
|---|
| | 40 | |
|---|
| | 41 | // definition of the required parameters |
|---|
| | 42 | $mail->setSender('webmaster@my-company.com', 'My Company webmaster'); |
|---|
| | 43 | $mail->setFrom('webmaster@my-company.com', 'My Company webmaster'); |
|---|
| | 44 | $mail->addReplyTo('webmaster_copy@my-company.com'); |
|---|
| | 45 | |
|---|
| | 46 | $mail->addAddress($customer->getEmail()); |
|---|
| | 47 | |
|---|
| | 48 | $mail->setSubject('Your password request'); |
|---|
| | 49 | $mail->setBody(' |
|---|
| | 50 | Dear customer, |
|---|
| | 51 | |
|---|
| | 52 | You are so absentminded. Next time, try to remember your password: |
|---|
| | 53 | '.$customer->getPassword().' |
|---|
| | 54 | |
|---|
| | 55 | Regards, |
|---|
| | 56 | The My Company webmaster'); |
|---|
| | 57 | |
|---|
| | 58 | // send the email |
|---|
| | 59 | $mail->send(); |
|---|
| | 60 | } |
|---|
| | 61 | |
|---|
| | 62 | Use of an alternate action |
|---|
| | 63 | -------------------------- |
|---|
| | 64 | |
|---|
| | 65 | In many cases, as the email sending process is just a detour in the logic of an action that does something else, it is often delegated to another action. Here is how it goes: |
|---|
| | 66 | |
|---|
| | 67 | [php] |
|---|
| | 68 | public function executePasswordRequest() |
|---|
| | 69 | { |
|---|
| | 70 | // send the email |
|---|
| | 71 | $raw_email = $this->sendEmail('mail', 'sendPassword'); |
|---|
| | 72 | |
|---|
| | 73 | // log the email |
|---|
| | 74 | $this->logMessage($raw_email, 'debug'); |
|---|
| | 75 | } |
|---|
| | 76 | |
|---|
| | 77 | The email sending is delegated to a `sendPassword` action of a `mail` module. The `->sendEmail()` method of the `sfAction` class is a special kind of `->forward()` that executes another action but comes back afterward (it doesn't stop the execution of the current action). In addition, it returns a raw email that can be written into a log file (you will find more information about the way to log information in the [debug chapter](debug.txt)). |
|---|
| | 78 | |
|---|
| | 79 | The `mail/sendPassword` deals with the `sfMail` object, but it doesn't need to require the class (it is autoloaded) nor to define the mailer (it is taken from a configuration file): |
|---|
| | 80 | |
|---|
| | 81 | [php] |
|---|
| | 82 | public function executeSendPassword() |
|---|
| | 83 | { |
|---|
| | 84 | // determine customer from the request 'id' parameter |
|---|
| | 85 | $customer = CustomerPeer::retrieveByPk($this->getRequestParameter('id')); |
|---|
| | 86 | |
|---|
| | 87 | // class initialization |
|---|
| | 88 | $mail = new sfMail(); |
|---|
| | 89 | $mail->setCharset('utf-8'); |
|---|
| | 90 | |
|---|
| | 91 | // definition of the required parameters |
|---|
| | 92 | $mail->setSender('webmaster@my-company.com', 'My Company webmaster'); |
|---|
| | 93 | $mail->setFrom('webmaster@my-company.com', 'My Company webmaster'); |
|---|
| | 94 | $mail->addReplyTo('webmaster_copy@my-company.com'); |
|---|
| | 95 | |
|---|
| | 96 | $mail->addAddress($customer->getEmail()); |
|---|
| | 97 | |
|---|
| | 98 | $mail->setSubject('Your password request'); |
|---|
| | 99 | |
|---|
| | 100 | $this->password = $customer->getPassword(); |
|---|
| | 101 | $this->mail = $mail; |
|---|
| | 102 | } |
|---|
| | 103 | |
|---|
| | 104 | Notice that the action doesn't need to call the `->send()` method for the `sfMail` object; being called by a `->sendEmail()`, it knows that it needs to finish by sending its `$this->mail` `sfMail` object. And where is the mail? will you ask. That's the beauty of the MVC separation: the body of the mail itself is to be written in the template `sendPasswordSuccess.php`: |
|---|
| | 105 | |
|---|
| | 106 | [php] |
|---|
| | 107 | Dear customer, |
|---|
| | 108 | |
|---|
| | 109 | You are so absentminded. Next time, try to remember your password: |
|---|
| | 110 | <?php echo $password ?> |
|---|
| | 111 | |
|---|
| | 112 | Regards, |
|---|
| | 113 | The My Company webmaster |
|---|
| | 114 | |
|---|
| | 115 | >**Note**: If the `sendPassword` action ever determines that the email doesn't have to be sent, it can still abort the emailing process by returning `sfView::NONE`, just like a regular action. |
|---|
| | 116 | |
|---|
| | 117 | Mailer configuration |
|---|
| | 118 | -------------------- |
|---|
| | 119 | |
|---|
| | 120 | If you use the alternate action method, you can (you don't have to) set the mailer and activate it environment by environment through a configuration file. |
|---|
| | 121 | |
|---|
| | 122 | Create a `mailer.yml` configuration file in the `modules/mail/config/` directory with: |
|---|
| | 123 | |
|---|
| | 124 | dev: |
|---|
| | 125 | deliver: off |
|---|
| | 126 | |
|---|
| | 127 | all: |
|---|
| | 128 | mailer: sendmail |
|---|
| | 129 | |
|---|
| | 130 | This stipulates the mailer program to be used to send mails, and deactivates the sending of mails in the development environment. |
|---|
| | 131 | |
|---|
| | 132 | Send HTML email |
|---|
| | 133 | --------------- |
|---|
| | 134 | |
|---|
| | 135 | Most of the time, emails are to be sent in HTML format, or even in a multipart format (enclosing both HTML and text format). To handle it directly with the `sfMail` object, use the `->setContentType()` method and specify an alternate body: |
|---|
| | 136 | |
|---|
| | 137 | [php] |
|---|
| | 138 | $mail->setContentType('text/html'); |
|---|
| | 139 | $mail->setAltBody(' |
|---|
| | 140 | <p>Dear customer</p>, |
|---|
| | 141 | <p> |
|---|
| | 142 | You are so <i>absentminded</i>. Next time, try to remember your password:<br> |
|---|
| | 143 | <b>'.$customer->getPassword().'</b> |
|---|
| | 144 | </p> |
|---|
| | 145 | <p> |
|---|
| | 146 | Regards,<br> |
|---|
| | 147 | The My Company webmaster |
|---|
| | 148 | </p>'); |
|---|
| | 149 | $mail->setAltBody(' |
|---|
| | 150 | Dear customer, |
|---|
| | 151 | |
|---|
| | 152 | You are so absentminded. Next time, try to remember your password: |
|---|
| | 153 | '.$customer->getPassword().' |
|---|
| | 154 | |
|---|
| | 155 | Regards, |
|---|
| | 156 | The My Company webmaster'); |
|---|
| | 157 | |
|---|
| | 158 | If you use an alternate action, you will just need to use an alternate template ending with `.altbody.php`. Symfony will automatically add it as alternate body: |
|---|
| | 159 | |
|---|
| | 160 | [php] |
|---|
| | 161 | // in sendPasswordSuccess.php |
|---|
| | 162 | <p>Dear customer</p>, |
|---|
| | 163 | <p> |
|---|
| | 164 | You are so <i>absentminded</i>. Next time, try to remember your password:<br> |
|---|
| | 165 | <b><?php echo $password ?></b> |
|---|
| | 166 | </p> |
|---|
| | 167 | <p> |
|---|
| | 168 | Regards,<br> |
|---|
| | 169 | The My Company webmaster |
|---|
| | 170 | </p> |
|---|
| | 171 | |
|---|
| | 172 | // in sendPasswordSuccess.altbody.php |
|---|
| | 173 | Dear customer, |
|---|
| | 174 | |
|---|
| | 175 | You are so absentminded. Next time, try to remember your password: |
|---|
| | 176 | <?php echo $password ?> |
|---|
| | 177 | |
|---|
| | 178 | Regards, |
|---|
| | 179 | The My Company webmaster |
|---|
| | 180 | |
|---|
| | 181 | >**Note**: If you just use an HTML version without altbody template, you will need to set the content type to `text/html` in the `sendPassword` action. |
|---|
| | 182 | |
|---|
| | 183 | Embed images |
|---|
| | 184 | ------------ |
|---|
| | 185 | |
|---|
| | 186 | HTML emails can contain images directly embedded in the body. To add an embedded image, use the `->addEmbeddedImage()` method of the `sfMail` object: |
|---|
| | 187 | |
|---|
| | 188 | [php] |
|---|
| | 189 | $mail->addEmbeddedImage(sfConfig::get('sf_web_dir').'/images/my_company_logo.gif', 'CID1', 'My Company Logo', 'base64', 'image/gif'); |
|---|
| | 190 | |
|---|
| | 191 | The first argument is the path to the image, the second is a reference of the image that you can use in the template to embed it: |
|---|
| | 192 | |
|---|
| | 193 | [php] |
|---|
| | 194 | // in sendPasswordSuccess.php |
|---|
| | 195 | <p>Dear customer</p>, |
|---|
| | 196 | <p> |
|---|
| | 197 | You are so <i>absentminded</i>. Next time, try to remember your password:<br> |
|---|
| | 198 | <b><?php echo $password ?></b> |
|---|
| | 199 | </p> |
|---|
| | 200 | <p> |
|---|
| | 201 | Regards,<br> |
|---|
| | 202 | The My Company webmaster |
|---|
| | 203 | <img src="cid:CID1" /> |
|---|
| | 204 | </p> |
|---|
| | 205 | |
|---|
| | 206 | Attachments |
|---|
| | 207 | ----------- |
|---|
| | 208 | |
|---|
| | 209 | Attaching a document to a mail is as simple as you would expect it to be: |
|---|
| | 210 | |
|---|
| | 211 | [php] |
|---|
| | 212 | // document attachment |
|---|
| | 213 | $mail->addAttachment(sfConfig::get('sf_data_dir').'/MyDocument.doc'); |
|---|
| | 214 | // string attachment |
|---|
| | 215 | $mail->addStringAttachment('this is some cool text to embed', 'file.txt'); |
|---|
| | 216 | |
|---|
| | 217 | Email addresses advanced syntax |
|---|
| | 218 | ------------------------------- |
|---|
| | 219 | |
|---|
| | 220 | In addition to recipients, emails often need to be sent as carbon copy ('cc:') or blind carbon copy ('bcc:'). Here is how to do this with `sfMail`: |
|---|
| | 221 | |
|---|
| | 222 | [php] |
|---|
| | 223 | $mail->addAddress($customer->getEmail()); |
|---|
| | 224 | $mail->addCc('carbon_copy@my-companyt.com '); |
|---|
| | 225 | $mail->addBcc('blind_carbon_copy@my-company.com'); |
|---|
| | 226 | |
|---|
| | 227 | The `sfMail` methods used to set emails (`->setSender()`, `->setFrom()`, `->addReplyTo()`, `->addAddress()`, `->addCc()`, `->addBcc()`) can use two syntaxes: |
|---|
| | 228 | |
|---|
| | 229 | [php] |
|---|
| 26 | | $mail->addReplyTo('you@symfony-project.com'); |
|---|
| 27 | | $mail->setCharset('utf-8'); |
|---|
| 28 | | $mail->setSubject('A very important matter'); |
|---|
| 29 | | $mail->setBody('First of all, you should know that...'); |
|---|
| 30 | | |
|---|
| 31 | | // send the email |
|---|
| 32 | | $mail->send(); |
|---|
| | 231 | // is equivalent to |
|---|
| | 232 | $mail->setFrom('me@symfony-project.com <Symfony>'); |
|---|
| | 233 | |
|---|
| | 234 | In addition, to minimize the code in case of multiple recipients, `sfMail` has an `->addAddresses()` method: |
|---|
| | 235 | |
|---|
| | 236 | [php] |
|---|
| | 237 | $mail->addAddress('client1@client.com <Jules>'); |
|---|
| | 238 | $mail->addAddress('client2@client.com <Jim>'); |
|---|
| | 239 | // is equivalent to |
|---|
| | 240 | $mail->addAddresses(array('client1@client.com <Jules>', 'client2@client.com <Jim>')); |
|---|
| | 241 | |
|---|
| | 242 | `sfMail` methods |
|---|
| | 243 | ---------------- |
|---|
| | 244 | |
|---|
| | 245 | Once you've built your `sfMail` object, you might want to check its content. Fortunately, all the setter methods described above have an equivalent getter method, and you can clear the properties previously set: |
|---|
| | 246 | |
|---|
| | 247 | [php] |
|---|
| | 248 | ->setCharset($charset) |
|---|
| | 249 | ->getCharset() |
|---|
| | 250 | ->setContentType($content_type) |
|---|
| | 251 | ->getContentType() |
|---|
| | 252 | ->setPriority($priority) |
|---|
| | 253 | ->getPriority() |
|---|
| | 254 | ->setEncoding($encoding) |
|---|
| | 255 | ->getEncoding() |
|---|
| | 256 | ->setSubject($subject) |
|---|
| | 257 | ->getSubject() |
|---|
| | 258 | ->setBody($body) |
|---|
| | 259 | ->getBody() |
|---|
| | 260 | ->setAltBody($text) |
|---|
| | 261 | ->getAltBody() |
|---|
| | 262 | ->setMailer($type = 'mail') |
|---|
| | 263 | ->getMailer() |
|---|
| | 264 | ->setSender($address, $name = null) |
|---|
| | 265 | ->getSender() |
|---|
| | 266 | ->setFrom($address, $name = null) |
|---|
| | 267 | ->getFrom() |
|---|
| | 268 | ->addAddresses($addresses) |
|---|
| | 269 | ->addAddress($address, $name = null) |
|---|
| | 270 | ->addCc($address, $name = null) |
|---|
| | 271 | ->addBcc($address, $name = null) |
|---|
| | 272 | ->addReplyTo($address, $name = null) |
|---|
| | 273 | ->clearAddresses() |
|---|
| | 274 | ->clearCcs() |
|---|
| | 275 | ->clearBccs() |
|---|
| | 276 | ->clearReplyTos() |
|---|
| | 277 | ->clearAllRecipients() |
|---|
| | 278 | ->addAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') |
|---|
| | 279 | ->addStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') |
|---|
| | 280 | ->addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') |
|---|
| | 281 | ->setAttachments($attachments) |
|---|
| | 282 | ->clearAttachments() |
|---|
| | 283 | ->addCustomHeader($name, $value) |
|---|
| | 284 | ->clearCustomHeaders() |
|---|
| | 285 | ->setWordWrap($wordWrap) |
|---|
| | 286 | ->getWordWrap() |
|---|