├── _config.php ├── bin ├── test-env-setup ├── test ├── test-clean ├── test-test └── test-build ├── _config └── config.yml ├── .gitignore ├── code ├── ForgotPasswordSMTPEmail.php ├── SMTP_LogEmailWriter.php ├── SMTPEmail.php └── SmtpMailer.php ├── .travis.yml ├── composer.json ├── README.md └── tests └── SMTPMailerTest.php /_config.php: -------------------------------------------------------------------------------- 1 | subject = _t('Member.SUBJECTPASSWORDRESET', "Your password reset link", 'Email subject'); 16 | } 17 | } -------------------------------------------------------------------------------- /code/SMTP_LogEmailWriter.php: -------------------------------------------------------------------------------- 1 | 4 | * https://github.com/deanrather 5 | */ 6 | class SMTP_LogEmailWriter extends SS_LogEmailWriter { 7 | 8 | /** 9 | * Send an email to the email address set in 10 | * this writer. 11 | */ 12 | public function _write($event) { 13 | // If no formatter set up, use the default 14 | if(!$this->_formatter) { 15 | $formatter = new SS_LogErrorEmailFormatter(); 16 | $this->setFormatter($formatter); 17 | } 18 | 19 | $formattedData = $this->_formatter->format($event); 20 | $subject = $formattedData['subject']; 21 | $data = $formattedData['data']; 22 | 23 | $email = new Email(); 24 | $email->setTo($this->emailAddress); 25 | $email->setSubject($subject); 26 | $email->setBody($data); 27 | $email->setFrom(self::$send_from); 28 | $email->send(); 29 | } 30 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - 5.4 4 | - 5.5 5 | - 5.6 6 | - 7.0 7 | 8 | env: 9 | matrix: 10 | - DB=MYSQL CORE_RELEASE=3.0 11 | - DB=MYSQL CORE_RELEASE=3.1 12 | - DB=MYSQL CORE_RELEASE=3.2 13 | - DB=MYSQL CORE_RELEASE=3.3 14 | - DB=MYSQL CORE_RELEASE=3.4 15 | - DB=MYSQL CORE_RELEASE=3.5 16 | - DB=MYSQL CORE_RELEASE=3.6 17 | 18 | matrix: 19 | allow_failures: 20 | - php: 7.0 21 | - php: 5.6 22 | env: DB=MYSQL CORE_RELEASE=master 23 | include: 24 | - php: 5.6 25 | env: DB=MYSQL CORE_RELEASE=master 26 | - php: 7.0 27 | env: DB=MYSQL CORE_RELEASE=master 28 | 29 | before_script: 30 | - phpenv rehash 31 | - composer self-update 32 | - git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support 33 | - php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss 34 | - cd ~/builds/ss 35 | 36 | script: 37 | - vendor/bin/phpunit abc-silverstripe-mailer/tests/ 38 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "azt3k/abc-silverstripe-mailer", 3 | "description": "Library that adds smtp mail support to Silverstripe", 4 | "license": "BSD-3-Clause-Clear", 5 | "type": "silverstripe-module", 6 | "authors": [ 7 | { 8 | "name": "Aaron Latham-Ilari", 9 | "email": "az@dev-io.us" 10 | } 11 | ], 12 | "minimum-stability": "dev", 13 | "require": { 14 | "php" : ">=5.3.0", 15 | "composer/installers" : ">=1.0", 16 | "silverstripe/framework" : "^3.0", 17 | "silverstripe/cms" : "^3.0", 18 | "phpmailer/phpmailer" : "~5.2.23" 19 | }, 20 | "require-dev": { 21 | "phpunit/PHPUnit" : "~3.7", 22 | "silverstripe/sqlite3" : "*" 23 | }, 24 | "extra": { 25 | "installer-paths": { 26 | "vendor/{$name}": [ 27 | "phpmailer/phpmailer" 28 | ] 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bin/test-build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | DIR=~/builds/abc-silverstripe-mailer 5 | 6 | export TRAVIS_BRANCH=1.0 7 | export TRAVIS_COMMIT=HEAD 8 | export TRAVIS_REPO_SLUG=azt3k/abc-silverstripe-mailer 9 | export DB=SQLITE 10 | export CORE_RELEASE=3.1 11 | 12 | # get to the right place 13 | cd $PDIR/.. 14 | 15 | # run the travis setup script 16 | mkdir -p $DIR 17 | git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git $DIR/travis-support 18 | php $DIR/travis-support/travis_setup.php --source $PDIR/.. --target $DIR/ss 19 | 20 | # make some mods to the project build 21 | mkdir $DIR/ss/silverstripe-cache 22 | 23 | # inject the autoloader 24 | # echo " 25 | # $DIR/ss/mysite/_config.php 40 | 41 | # apply patch 42 | # echo " 46 | # " | cat - $DIR/ss/framework/dev/SapphireTestReporter.php > /tmp/out && mv /tmp/out $DIR/ss/framework/dev/SapphireTestReporter.php 47 | sed -i "s/if(\!class_exists('PHPUnit_Framework_TestResult', false)) require_once 'PHPUnit\/Framework\/TestResult.php';/if (\!class_exists('PHPUnit_Framework_TestResult')) require_once 'PHPUnit\/Framework\/TestResult.php';/g" $DIR/ss/framework/dev/SapphireTestReporter.php 48 | sed -i "s/if(\!class_exists('PHPUnit_Framework_TestListener', false)) require_once 'PHPUnit\/Framework\/TestListener.php';/if (\!interface_exists('PHPUnit_Framework_TestListener')) require_once 'PHPUnit\/Framework\/TestListener.php';/g" $DIR/ss/framework/dev/SapphireTestReporter.php 49 | 50 | #sed -i "s/if(\!class_exists('PHPUnit_Framework_TestResult', false)) require_once 'PHPUnit\/Framework\/TestResult.php';/if (!class_exists('PHPUnit_Framework_TestResult')) require_once 'PHPUnit/Framework/TestResult.php';/g" ~/builds/abc-silverstripe-mailer/ss/framework/dev/SapphireTestReporter.php 51 | 52 | 53 | # "redeploy" 54 | rm -rf $DIR/ss/abc-silverstripe-mailer 55 | cp -rf $PDIR/.. $DIR/ss/abc-silverstripe-mailer 56 | 57 | bash $DIR/ss/framework/sake dev/build 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/azt3k/abc-silverstripe-mailer.svg?branch=master)](https://travis-ci.org/azt3k/abc-silverstripe-mailer) 2 | 3 | Setup 4 | ----- 5 | 6 | Add the following to you composer.json file: 7 | 8 | ```json 9 | "require": { 10 | "azt3k/abc-silverstripe-mailer" : "*@stable" 11 | } 12 | ``` 13 | 14 | Add something like the following your `mysite/_config.php` file: 15 | 16 | ````php 17 | SmtpMailer::set_conf(array( 18 | 'default_from' => array( 19 | 'name' => 'admin', 20 | 'email' => 'admin@localhost' 21 | ), 22 | 'charset_encoding' => 'utf-8', 23 | 'server' => 'localhost', 24 | 'port' => 25, 25 | 'secure' => null, 26 | 'authenticate' => false, 27 | 'user' => 'username', 28 | 'pass' => 'password', 29 | 'debug' => 0, 30 | 'lang' => 'en' 31 | )); 32 | ```` 33 | or 34 | 35 | ````php 36 | SmtpMailer::set_conf(array( 37 | 'default_from' => array( 38 | 'name' => 'user', 39 | 'email' => 'user@gmail.com' 40 | ), 41 | 'charset_encoding' => 'utf-8', 42 | 'server' => 'smtp.gmail.com', 43 | 'port' => 587, 44 | 'secure' => 'tls', 45 | 'authenticate' => true, 46 | 'user' => 'user@gmail.com', 47 | 'pass' => 'password', 48 | 'debug' => 0, 49 | 'lang' => 'en' 50 | )); 51 | ```` 52 | 53 | Alternatively insert the configuration into your `project/_config/config.yml` file 54 | 55 | ````yaml 56 | SmtpMailer: 57 | conf: 58 | default_from: 59 | name: user 60 | email: user@gmail.com 61 | charset_encoding: utf-8 62 | server: smtp.gmail.com 63 | port: 587 64 | secure: tls 65 | authenticate: true 66 | user: user@gmail.com 67 | pass: password' 68 | debug: 0 69 | lang: en 70 | ```` 71 | 72 | 73 | License 74 | ------- 75 | 76 | Copyright (c) 2018 Aaron Latham-Ilari 77 | 78 | All rights reserved. 79 | 80 | Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) provided that the following conditions are met: 81 | 82 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 83 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 84 | * Neither the name of [Owner Organization] nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 85 | 86 | NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 87 | 88 | -------------------------------------------------------------------------------- /code/SMTPEmail.php: -------------------------------------------------------------------------------- 1 | customHeaders; 11 | return !empty($h['Reply-To']) ? $h['Reply-To'] : null; 12 | } 13 | 14 | /** 15 | * makes ReplyTo work like BCC etc 16 | * @param [type] $val [description] 17 | */ 18 | public function setReplyTo($val) { 19 | $this->addCustomHeader('Reply-To', $val); 20 | return $this; 21 | } 22 | 23 | /** 24 | * proxy method for file attachments 25 | * @param [type] $filename [description] 26 | * @param [type] $attachedFilename [description] 27 | * @param [type] $mimetype [description] 28 | * @return [type] [description] 29 | */ 30 | public function attachFile($filename, $attachedFilename = null, $mimetype = null) { 31 | 32 | // generate a name for the file if we aren't supplied one 33 | if (!$attachedFilename) $attachedFilename = trim(str_replace(Director::baseFolder(), '', $filename), '/'); 34 | 35 | // Get the full path 36 | if (!file_exists($filename)) $filename = Director::getAbsFile($filename); 37 | 38 | // try to attach the file 39 | if (file_exists($filename)) { 40 | $this->attachFileFromString(file_get_contents($filename), $attachedFilename, $mimetype); 41 | } 42 | 43 | // throw 44 | else { 45 | throw new Exception("Could not attach '$filename' to email. File does not exist."); 46 | } 47 | 48 | return $this; 49 | } 50 | 51 | public function Absolute($link) { 52 | return Director::protocolAndHost() . str_replace('//','/', '/' . $link); 53 | } 54 | 55 | /** 56 | * this is mainly a test harness 57 | * @return [type] [description] 58 | */ 59 | public function setupMailer() { 60 | 61 | Requirements::clear(); 62 | 63 | $this->parseVariables(true); 64 | 65 | if(empty($this->from)) $this->from = Email::config()->admin_email; 66 | 67 | $headers = $this->customHeaders; 68 | 69 | if(project()) $headers['X-SilverStripeSite'] = project(); 70 | 71 | $to = $this->to; 72 | $from = $this->from; 73 | $subject = $this->subject; 74 | if ($sendAllTo = $this->config()->send_all_emails_to) { 75 | $subject .= " [addressed to $to"; 76 | $to = $sendAllTo; 77 | if($this->cc) $subject .= ", cc to $this->cc"; 78 | if($this->bcc) $subject .= ", bcc to $this->bcc"; 79 | $subject .= ']'; 80 | unset($headers['Cc']); 81 | unset($headers['Bcc']); 82 | } else { 83 | if($this->cc) $headers['Cc'] = $this->cc; 84 | if($this->bcc) $headers['Bcc'] = $this->bcc; 85 | } 86 | 87 | if ($ccAllTo = $this->config()->cc_all_emails_to) { 88 | if(!empty($headers['Cc']) && trim($headers['Cc'])) { 89 | $headers['Cc'] .= ', ' . $ccAllTo; 90 | } else { 91 | $headers['Cc'] = $ccAllTo; 92 | } 93 | } 94 | 95 | if ($bccAllTo = $this->config()->bcc_all_emails_to) { 96 | if(!empty($headers['Bcc']) && trim($headers['Bcc'])) { 97 | $headers['Bcc'] .= ', ' . $bccAllTo; 98 | } else { 99 | $headers['Bcc'] = $bccAllTo; 100 | } 101 | } 102 | 103 | if ($sendAllfrom = $this->config()->send_all_emails_from) { 104 | if($from) $subject .= " [from $from]"; 105 | $from = $sendAllfrom; 106 | } 107 | 108 | Requirements::restore(); 109 | 110 | return self::mailer()->setupMailer($to, $from, $subject, $this->attachments, $headers); 111 | 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /tests/SMTPMailerTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('SmtpMailer', get_class($mailer)); 13 | 14 | $mailer = SMTPEmail::mailer(); 15 | $this->assertEquals('SmtpMailer', get_class($mailer)); 16 | } 17 | 18 | /** 19 | * @depends testSetup 20 | */ 21 | public function testSMTPMailerSetConf() { 22 | 23 | // phpunit is a bit broken so we manually call the dependent tests; 24 | $this->testSetup(); 25 | 26 | $conf_in = array( 27 | 'default_from' => array( 28 | 'name' => 'abc-silverstripe-mailer-from', 29 | 'email' => 'abc-silverstripe-mailer-from@mailinator.com' 30 | ), 31 | 'charset_encoding' => 'utf-8', 32 | 'server' => 'mail.mailinator.com', 33 | 'port' => 25, 34 | 'secure' => null, 35 | 'authenticate' => false, 36 | 'user' => '', 37 | 'pass' => '', 38 | 'debug' => 0, 39 | 'lang' => 'en' 40 | ); 41 | 42 | SMTPMailer::set_conf($conf_in); 43 | 44 | $conf_out = (array) SMTPMailer::get_conf(); 45 | 46 | $this->assertEquals($conf_in, $conf_out); 47 | } 48 | 49 | /** 50 | * @depends testSMTPMailerSetConf 51 | */ 52 | public function testEmail() { 53 | 54 | // phpunit is a bit broken so we manually call the dependent tests; 55 | $this->testSMTPMailerSetConf(); 56 | 57 | $e = new Email(); 58 | $e->To = "abc-silverstripe-mailer@mailinator.com"; 59 | $e->Subject = "Hi there"; 60 | $e->Body = "I just really wanted to email you and say hi."; 61 | 62 | $this->assertEquals(true, $e->send()); 63 | 64 | } 65 | 66 | /** 67 | * @depends testSMTPMailerSetConf 68 | */ 69 | public function testSMTPEmail() { 70 | 71 | // phpunit is a bit broken so we manually call the dependent tests; 72 | $this->testSMTPMailerSetConf(); 73 | 74 | $e = new SMTPEmail(); 75 | $e->To = "abc-silverstripe-mailer@mailinator.com"; 76 | $e->Subject = "Hi there"; 77 | $e->Body = "I just really wanted to email you and say hi."; 78 | 79 | $this->assertEquals(true, $e->send()); 80 | 81 | } 82 | 83 | // disabling this test because Email Doesn't come out as SMTP email in these tests 84 | // /** 85 | // * @depends testEmail 86 | // */ 87 | // public function testEmailCustomHeaders() { 88 | // 89 | // // phpunit is a bit broken so we manually call the dependent tests; 90 | // $this->testEmail(); 91 | // 92 | // $bcc = "abc-silverstripe-mailer-bcc@mailinator.com"; 93 | // $cc = "abc-silverstripe-mailer-cc@mailinator.com"; 94 | // $replyto = "abc-silverstripe-mailer-reply-to@mailinator.com"; 95 | // 96 | // $e = new Email(); 97 | // $e->To = "abc-silverstripe-mailer@mailinator.com"; 98 | // $e->Subject = "Hi there"; 99 | // $e->Body = "I just really wanted to email you and say hi."; 100 | // $e->Cc = $cc; 101 | // $e->Bcc = $bcc; 102 | // $e->ReplyTo = $replyto; 103 | // 104 | // // get the mailer bound to the Email class 105 | // $e->setupMailer(); 106 | // $mailer = Email::mailer()->mailer; 107 | // 108 | // // check bccs 109 | // $bccs = $mailer->getBccAddresses(); 110 | // $this->assertEquals(true, in_array($bcc, $bccs)); 111 | // 112 | // // check ccs 113 | // $ccs = $mailer->getCcAddresses(); 114 | // $this->assertEquals(true, in_array($cc, $ccs)); 115 | // 116 | // // check replytos 117 | // $replytos = $mailer->getReplyToAddresses(); 118 | // $this->assertEquals(true, in_array($reployto, $reploytos)); 119 | // 120 | // // check send 121 | // // $this->assertEquals(true, $e->send()); 122 | // 123 | // } 124 | 125 | /** 126 | * @depends testSMTPEmail 127 | */ 128 | public function testSMTPEmailCustomHeaders() 129 | { 130 | 131 | // phpunit is a bit broken so we manually call the dependent tests; 132 | $this->testSMTPEmail(); 133 | 134 | $bcc = "abc-silverstripe-mailer-bcc@mailinator.com"; 135 | $cc = "abc-silverstripe-mailer-cc@mailinator.com"; 136 | $replyto = "abc-silverstripe-mailer-reply-to@mailinator.com"; 137 | 138 | $e = new SMTPEmail(); 139 | $e->To = "abc-silverstripe-mailer@mailinator.com"; 140 | $e->Subject = "Hi there"; 141 | $e->Body = "I just really wanted to email you and say hi."; 142 | $e->Cc = $cc; 143 | $e->Bcc = $bcc; 144 | $e->ReplyTo = $replyto; 145 | 146 | // get the mailer bound to the Email class 147 | $e->setupMailer(); 148 | $mailer = SMTPEmail::mailer()->mailer; 149 | 150 | // check bccs 151 | $bccs = $mailer->getBccAddresses(); 152 | $exists = false; 153 | foreach ($bccs as $item) { 154 | if (in_array($bcc, $item)) $exists = true; 155 | } 156 | $this->assertEquals(true, $exists); 157 | 158 | // check ccs 159 | $ccs = $mailer->getCcAddresses(); 160 | $exists = false; 161 | foreach ($ccs as $item) { 162 | if (in_array($cc, $item)) $exists = true; 163 | } 164 | $this->assertEquals(true, $exists); 165 | 166 | // check replytos 167 | $replytos = $mailer->getReplyToAddresses(); 168 | $exists = false; 169 | foreach ($replytos as $item) { 170 | if (in_array($replyto, $item)) $exists = true; 171 | } 172 | $this->assertEquals(true, $exists); 173 | 174 | // check send 175 | $this->assertEquals(true, $e->send()); 176 | 177 | } 178 | 179 | /** 180 | * @depends testSMTPEmailCustomHeaders 181 | */ 182 | public function testMultipleRecipients() { 183 | 184 | // phpunit is a bit broken so we manually call the dependent tests; 185 | $this->testSMTPEmailCustomHeaders(); 186 | 187 | $to = 'abc-silverstripe-mailer@mailinator.com'; 188 | $to2 = 'abc-silverstripe-mailer-2@mailinator.com'; 189 | 190 | $e = new SMTPEmail(); 191 | $e->To = $to . ', ' . $to2; 192 | $e->Subject = "Hi there"; 193 | $e->Body = "I just really wanted to email you and say hi."; 194 | 195 | // get the mailer bound to the Email class 196 | $e->setupMailer(); 197 | $mailer = SMTPEmail::mailer()->mailer; 198 | 199 | // check recipients 200 | $tos = $mailer->getToAddresses(); 201 | $exists = $exists2 = false; 202 | foreach ($tos as $item) { 203 | if (in_array($to, $item)) $exists = true; 204 | if (in_array($to2, $item)) $exists2 = true; 205 | } 206 | $this->assertEquals(true, $exists && $exists2); 207 | 208 | // check send 209 | $this->assertEquals(true, $e->send()); 210 | 211 | } 212 | 213 | /** 214 | * @depends testSMTPEmail 215 | */ 216 | public function testFSAttachmentEmail() { 217 | 218 | // phpunit is a bit broken so we manually call the dependent tests; 219 | $this->testSMTPEmail(); 220 | 221 | // create file 222 | $fileContents = 'test content'; 223 | $fileName = 'test.txt'; 224 | $type = 'text/plain'; 225 | $absFileName = sys_get_temp_dir() . '/' . $fileName; 226 | file_put_contents($absFileName, $fileContents); 227 | 228 | // create email 229 | $e = new SMTPEmail(); 230 | $e->To = 'abc-silverstripe-mailer@mailinator.com'; 231 | $e->Subject = "Hi there"; 232 | $e->Body = "I just really wanted to email you and say hi."; 233 | $e->attachFile($absFileName, $fileName, $type); 234 | 235 | // get the mailer bound to the Email class 236 | $e->setupMailer(); 237 | $mailer = SMTPEmail::mailer()->mailer; 238 | 239 | // check attached files 240 | $files = $mailer->getAttachments(); 241 | $this->assertEquals(true, $files[0][0] == $fileContents); 242 | $this->assertEquals(true, $files[0][1] == $fileName); 243 | $this->assertEquals(true, $files[0][4] == $type); 244 | 245 | // check send 246 | $this->assertEquals(true, $e->send()); 247 | 248 | } 249 | 250 | /** 251 | * @depends testSMTPEmail 252 | */ 253 | public function testStringAttachmentEmail() { 254 | 255 | // phpunit is a bit broken so we manually call the dependent tests; 256 | $this->testSMTPEmail(); 257 | 258 | // create file 259 | $fileContents = 'test content 2'; 260 | $fileName = 'test2.txt'; 261 | $type = 'text/plain'; 262 | 263 | // create email 264 | $e = new SMTPEmail(); 265 | $e->To = 'abc-silverstripe-mailer@mailinator.com'; 266 | $e->Subject = "Hi there"; 267 | $e->Body = "I just really wanted to email you and say hi."; 268 | $e->attachFileFromString($fileContents, $fileName, $type); 269 | 270 | // get the mailer bound to the Email class 271 | $e->setupMailer(); 272 | $mailer = SMTPEmail::mailer()->mailer; 273 | 274 | // check attached files 275 | $files = $mailer->getAttachments(); 276 | $this->assertEquals(true, $files[0][0] == $fileContents); 277 | $this->assertEquals(true, $files[0][1] == $fileName); 278 | $this->assertEquals(true, $files[0][4] == $type); 279 | 280 | // check send 281 | $this->assertEquals(true, $e->send()); 282 | 283 | } 284 | 285 | /** 286 | * @depends testSMTPEmail 287 | */ 288 | public function testForgotPasswordEmail() { 289 | 290 | // phpunit is a bit broken so we manually call the dependent tests; 291 | $this->testSMTPEmail(); 292 | 293 | $e = new ForgotPasswordSMTPEmail(); 294 | 295 | $this->assertEquals('ForgotPasswordEmail', $e->ss_template); 296 | } 297 | 298 | /** 299 | * @depends testForgotPasswordEmail 300 | */ 301 | public function testForgotPasswordSend() { 302 | 303 | // phpunit is a bit broken so we manually call the dependent tests; 304 | $this->testForgotPasswordEmail(); 305 | 306 | $data = Array ( 307 | 'FirstName' => 'John', 308 | 'PasswordResetLink' => '/reset-link-123', 309 | 'AbsoluteBaseURL' => 'www.silverstripe.com' 310 | ); 311 | 312 | $to = 'abc@silverstripe.co.nz'; 313 | 314 | $e = Member_ForgotPasswordEmail::create(); 315 | $e->populateTemplate($data); 316 | $e->setTo($to); 317 | 318 | $this->assertEquals(true, $e->send()); 319 | } 320 | 321 | } 322 | -------------------------------------------------------------------------------- /code/SmtpMailer.php: -------------------------------------------------------------------------------- 1 | array( 9 | 'name' => 'admin', 10 | 'email' => 'admin@localhost' 11 | ), 12 | 'charset_encoding' => 'utf-8', 13 | 'server' => 'localhost', 14 | 'port' => 25, 15 | 'secure' => null, 16 | 'authenticate' => false, 17 | 'user' => '', 18 | 'pass' => '', 19 | 'debug' => 0, 20 | 'lang' => 'en' 21 | ); 22 | 23 | /** 24 | * @config 25 | */ 26 | private static $conf = array(); 27 | 28 | /** 29 | * Constructor 30 | * 31 | * @param Mailer $mailer 32 | */ 33 | public function __construct($mailer = null) { 34 | $this->mailer = $mailer; 35 | } 36 | 37 | /** 38 | * @param array|object $conf An associative array containing the configuration - see static::$conf for an example 39 | * @return void 40 | */ 41 | public static function set_conf($conf) { 42 | $conf = (array) $conf; 43 | static::$conf = static::array_merge_recursive_distinct(static::$conf, $conf); 44 | } 45 | 46 | /** 47 | * @return stdClass 48 | */ 49 | public static function get_conf() { 50 | return (object) static::array_merge_recursive_distinct(static::$defaults, static::$conf); 51 | } 52 | 53 | /** 54 | * @return void 55 | */ 56 | protected static function set_conf_from_yaml() { 57 | $conf = (array) Config::inst()->get('SmtpMailer', 'conf'); 58 | // die(print_r($conf,1)); 59 | if (!empty($conf)) 60 | static::$conf = static::array_merge_recursive_distinct(static::$conf, $conf); 61 | } 62 | 63 | /** 64 | * @return void 65 | */ 66 | public function configure() { 67 | 68 | // configure from YAML if available 69 | static::set_conf_from_yaml(); 70 | 71 | // get the configuration 72 | $conf = static::get_conf(); 73 | 74 | if (!$this->mailer) { 75 | 76 | // configure PHP mailer 77 | $this->mailer = new PHPMailer(true); 78 | $this->mailer->IsSMTP(); 79 | $this->mailer->CharSet = $conf->charset_encoding; 80 | $this->mailer->Host = $conf->server; 81 | $this->mailer->Port = $conf->port; 82 | $this->mailer->SMTPSecure = $conf->secure; 83 | $this->mailer->SMTPAuth = $conf->authenticate; 84 | $this->mailer->SMTPDebug = $conf->debug; 85 | $this->mailer->SetLanguage($conf->lang); 86 | 87 | // auth? 88 | if ($this->mailer->SMTPAuth) { 89 | $this->mailer->Username = $conf->user; 90 | $this->mailer->Password = $conf->pass; 91 | } 92 | } 93 | 94 | // chain me 95 | return $this; 96 | } 97 | 98 | /** 99 | * Overwriting Mailer's function 100 | * 101 | * @param string $to the recipient 102 | * @param string $from the sender 103 | * @param string $subject the subject 104 | * @param string $plainContent plain text content 105 | * @param array $attachedFiles an array of files to attach 106 | * @param array $customheaders an array of custom headers to attach 107 | * @return boolean 108 | */ 109 | public function sendPlain($to, $from, $subject, $plainContent, $attachedFiles = array(), $customheaders = false) { 110 | $this->configure(); 111 | $this->mailer->IsHTML( false ); 112 | $this->mailer->Body = $plainContent; 113 | return $this->sendMailViaSmtp( $to, $from, $subject, $attachedFiles, $customheaders, false ); 114 | } 115 | 116 | 117 | /** 118 | * Overwriting Mailer's function 119 | * 120 | * @param string $to the recipient 121 | * @param string $from the sender 122 | * @param string $subject the subject 123 | * @param string $htmlContent html content 124 | * @param array $attachedFiles an array of files to attach 125 | * @param array $customheaders an array of custom headers to attach 126 | * @param string $plainContent plaintext alternative 127 | * @param array $inlineImages an array of image files to attach inline 128 | * @return boolean 129 | */ 130 | public function sendHTML( 131 | $to, 132 | $from, 133 | $subject, 134 | $htmlContent, 135 | $attachedFiles = array(), 136 | $customheaders = false, 137 | $plainContent = false, 138 | $inlineImages = false 139 | ) { 140 | 141 | $this->configure(); 142 | $this->mailer->IsHTML(true); 143 | 144 | if ($inlineImages) { 145 | $this->mailer->MsgHTML($htmlContent, Director::baseFolder()); 146 | } 147 | else { 148 | $this->mailer->Body = $htmlContent; 149 | if (empty($plainContent)) $plainContent = trim(Convert::html2raw($htmlContent)); 150 | $this->mailer->AltBody = $plainContent; 151 | } 152 | 153 | return $this->sendMailViaSmtp($to, $from, $subject, $attachedFiles, $customheaders, $inlineImages); 154 | } 155 | 156 | /** 157 | * @param string $to the recipient 158 | * @param string $from the sender 159 | * @param string $subject the subject 160 | * @param array $attachedFiles an array of files to attach 161 | * @param array $customheaders an array of custom headers to attach 162 | * @param array $inlineImages an array of image files to attach inline 163 | * @return boolean 164 | */ 165 | public function setupMailer($to, $from, $subject, $attachedFiles = array(), $customheaders = false) { 166 | 167 | // init this for later if we need it 168 | $msgForLog = ''; 169 | 170 | // make sure we have a mailer 171 | if (!$this->mailer) $this->configure(); 172 | 173 | // default result 174 | $result = false; 175 | 176 | // default from 177 | if (!$from) $from = static::$conf['default_from']['email']; 178 | 179 | // try to update stuff 180 | try { 181 | 182 | $this->buildBasicMail($to, $from, $subject); 183 | $this->addCustomHeaders($customheaders); 184 | $this->attachFiles((array) $attachedFiles); 185 | $result = true; 186 | 187 | } 188 | catch (phpmailerException $e) { 189 | $this->handleError($e->errorMessage(), $msgForLog); 190 | } 191 | catch (Exception $e) { 192 | $this->handleError($e->getMessage(), $msgForLog); 193 | } 194 | 195 | return $result; 196 | } 197 | 198 | /** 199 | * @param string $to the recipient 200 | * @param string $from the sender 201 | * @param string $subject the subject 202 | * @param array $attachedFiles an array of files to attach 203 | * @param array $customheaders an array of custom headers to attach 204 | * @param array $inlineImages an array of image files to attach inline 205 | * @return boolean 206 | */ 207 | protected function sendMailViaSmtp( 208 | $to, 209 | $from, 210 | $subject, 211 | $attachedFiles = array(), 212 | $customheaders = false, 213 | $inlineImages = false 214 | ) { 215 | 216 | // default result 217 | $result = false; 218 | 219 | if ($this->mailer->SMTPDebug > 0) 220 | echo "*** Debug mode is on, printing debug messages and not redirecting to the website:
"; 221 | 222 | $msgForLog = "\n*** The sender was : $from\n*** The message was :\n{$this->mailer->AltBody}\n"; 223 | 224 | try { 225 | 226 | // try to send 227 | if ($this->setupMailer($to, $from, $subject, $attachedFiles, $customheaders)) 228 | $result = $this->mailer->send(); 229 | 230 | if ($this->mailer->SMTPDebug > 0) { 231 | echo "*** E-mail to $to has been sent.
"; 232 | echo "*** The debug mode blocked the process to avoid the url redirection. So the CC e-mail is not sent."; 233 | } 234 | 235 | } 236 | catch(phpmailerException $e) { 237 | $this->handleError($e->errorMessage(), $msgForLog); 238 | } 239 | catch(Exception $e) { 240 | $this->handleError($e->getMessage(), $msgForLog); 241 | } 242 | 243 | return $result; 244 | } 245 | 246 | /** 247 | * @param string $e The error message - usually Exception::errorMessage() 248 | * @param string $msgForLog The message for the SS log 249 | * @param return void 250 | */ 251 | public function handleError($e, $msgForLog) { 252 | $msg = $e . $msgForLog; 253 | SS_Log::log($msg, Zend_Log::ERR); 254 | throw new Exception($msg); 255 | } 256 | 257 | /** 258 | * @param string $to 259 | * @param string $from 260 | * @param string $subject 261 | * @return void 262 | */ 263 | protected function buildBasicMail($to, $from, $subject) { 264 | 265 | if (preg_match('/(\'|")(.*?)\1[ ]+<[ ]*(.*?)[ ]*>/', $from, $from_split)) { 266 | // If $from countain a name, e.g. "My Name" 267 | $this->mailer->SetFrom( $from_split[3], $from_split[2] ); 268 | } 269 | else { 270 | $this->mailer->SetFrom( $from ); 271 | } 272 | 273 | // set subject 274 | $this->mailer->Subject = $subject; 275 | 276 | // clear addresses 277 | $this->mailer->ClearAddresses(); 278 | 279 | // clear attachments 280 | $this->mailer->ClearAttachments(); 281 | 282 | // split addresses 283 | $tos = explode(',', $to); 284 | 285 | // add addresses 286 | foreach ($tos as $addr) { 287 | 288 | // clean 289 | $addr = trim($addr); 290 | 291 | // validate 292 | // if (Email::validEmailAddress($addr)) { 293 | 294 | // For the recipient's name, the string before the @ from the e-mail address is used 295 | // this doesn't support the "Mr Nobody " syntax 296 | $this->mailer->AddAddress($addr, ucfirst(substr($addr, 0, strpos( $addr, '@' )))); 297 | // } 298 | } 299 | 300 | } 301 | 302 | /** 303 | * @param array $headers 304 | * @return void 305 | */ 306 | protected function addCustomHeaders( $headers ) { 307 | 308 | if( !$headers or !is_array($headers) ) $headers = array(); 309 | if( !isset( $headers["X-Mailer"] ) ) $headers["X-Mailer"] = X_MAILER; 310 | if( !isset( $headers["X-Priority"] ) ) $headers["X-Priority"] = 3; 311 | 312 | // clear existing headers 313 | $this->mailer->ClearCustomHeaders(); 314 | 315 | // look at all the headers and handle appropriately 316 | foreach ($headers as $header_name => $header_value) { 317 | 318 | // split 319 | if (in_array(strtolower($header_name), array('cc', 'bcc', 'reply-to', 'replyto'))) 320 | $addresses = preg_split('/(,|;)/', $header_value); 321 | 322 | // call setters rather than setting headers for: 323 | // - bcc 324 | // - cc 325 | // - reply-to 326 | switch (strtolower($header_name)) { 327 | case 'cc': 328 | foreach ($addresses as $address) { 329 | $this->mailer->addCC($address); 330 | } 331 | break; 332 | case 'bcc': 333 | foreach ($addresses as $address) { 334 | $this->mailer->addBCC($address); 335 | } 336 | break; 337 | case 'reply-to': 338 | case 'replyto': 339 | foreach ($addresses as $address) { 340 | $this->mailer->addReplyTo($address); 341 | } 342 | break; 343 | default: 344 | $this->mailer->AddCustomHeader($header_name . ':' . $header_value); 345 | break; 346 | } 347 | } 348 | } 349 | 350 | /** 351 | * @param array $attachedFiles 352 | * @return void 353 | */ 354 | protected function attachFiles(array $attachedFiles) { 355 | if (!empty($attachedFiles) && is_array($attachedFiles)) { 356 | foreach ($attachedFiles as $attachedFile) { 357 | 358 | // all attached files are stashed as strings in the attached files array 359 | // see Email and SMTPEMail classes for more info 360 | $this->mailer->AddStringAttachment( 361 | $attachedFile['contents'], 362 | $attachedFile['filename'], 363 | 'base64', 364 | $attachedFile['mimetype'] 365 | ); 366 | } 367 | } 368 | } 369 | 370 | /** 371 | * @param array $array1 The first array 372 | * @param array $array2 The second array 373 | * @return array the merged array 374 | */ 375 | protected static function array_merge_recursive_distinct( array $array1, array $array2 ) { 376 | 377 | $merged = $array1; 378 | 379 | foreach ($array2 as $key => $value) { 380 | 381 | if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) { 382 | $merged[$key] = static::array_merge_recursive_distinct($merged[$key], $value); 383 | } 384 | else { 385 | $merged[$key] = $value; 386 | } 387 | } 388 | 389 | return $merged; 390 | } 391 | 392 | } 393 | --------------------------------------------------------------------------------