├── .circleci └── config.yml ├── .gitignore ├── .travis.yml ├── README.md ├── README_old.md ├── VERSION ├── composer.json ├── phpunit.xml ├── src ├── SimpleEmailService.php ├── SimpleEmailServiceMessage.php └── SimpleEmailServiceRequest.php └── tests ├── SimpleEmailServiceMessageTest.php ├── SimpleEmailServiceRequestTest.php └── SimpleEmailServiceTest.php /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # PHP CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-php/ for more details 4 | # 5 | version: 2 6 | jobs: 7 | build: 8 | docker: 9 | # specify the version you desire here 10 | - image: circleci/php:7.1-node-browsers 11 | 12 | # Specify service dependencies here if necessary 13 | # CircleCI maintains a library of pre-built images 14 | # documented at https://circleci.com/docs/2.0/circleci-images/ 15 | # - image: circleci/mysql:9.4 16 | 17 | working_directory: ~/repo 18 | 19 | steps: 20 | - checkout 21 | - run: sudo apt update # PHP CircleCI 2.0 Configuration File# PHP CircleCI 2.0 Configuration File sudo apt install zlib1g-dev libsqlite3-dev 22 | - run: sudo docker-php-ext-install zip 23 | 24 | # Download and cache dependencies 25 | - restore_cache: 26 | keys: 27 | - v1-dependencies-{{ checksum "composer.json" }} 28 | # fallback to using the latest cache if no exact match is found 29 | - v1-dependencies- 30 | 31 | - run: composer install -n --prefer-dist 32 | 33 | - save_cache: 34 | key: v1-dependencies-{{ checksum "composer.json" }} 35 | paths: 36 | - ./vendor 37 | 38 | # run tests! 39 | - run: ./vendor/bin/phpunit -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | vendor 4 | composer.lock 5 | coverage 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 7.1 5 | - 7.2 6 | 7 | install: 8 | - composer install -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Amazon Simple Email Service provides a simple way to send e-mails without having to maintain your own mail server. Those PHP classes use the REST-based interface to that service.** 2 | 3 | [![Build Status](https://travis-ci.org/daniel-zahariev/php-aws-ses.svg?branch=master)](https://travis-ci.org/daniel-zahariev/php-aws-ses) 4 | [![CircleCI](https://circleci.com/gh/daniel-zahariev/php-aws-ses/tree/master.svg?style=svg)](https://circleci.com/gh/daniel-zahariev/php-aws-ses/tree/master) 5 | 6 | --- 7 | 8 | > This repository is a fork from version 0.8.2 of the [original classes](http://www.orderingdisorder.com/aws/ses/) developed by **Dan Myers** 9 | > Read the [old docs here](README_old.md) 10 | 11 | --- 12 | 13 | ## Table of Contents 14 | 15 | * [Installation](#installation) 16 | * [Basic Usage](#basic-usage) 17 | * [Recipients](#recipients) 18 | * [Message body](#message-body) 19 | * [Attachments](#attachments) 20 | * [Sending Bulk Messages](#sending-bulk-messages) 21 | * [API Endpoints](#api-endpoints) 22 | * [Helper Methods](#helper-methods) 23 | 24 | ### Installation 25 | 26 | Install the latest version with 27 | 28 | composer require daniel-zahariev/php-aws-ses 29 | 30 | ### Basic Usage 31 | 32 | ```php 33 | addTo('Recipient Name '); 39 | $m->setFrom('Sender '); 40 | $m->setSubject('Hello, world!'); 41 | $m->setMessageFromString('This is the message body.'); 42 | 43 | $ses = new SimpleEmailService('AccessKey', 'SecretKey'); 44 | print_r($ses->sendEmail($m)); 45 | 46 | // Successful response should print something similar to: 47 | //Array( 48 | // [MessageId] => 0000012dc5e4b4c0-b2c566ad-dcd0-4d23-bea5-f40da774033c-000000 49 | // [RequestId] => 4953a96e-29d4-11e0-8907-21df9ed6ffe3 50 | //) 51 | ``` 52 | 53 | ### Recipients 54 | 55 | ```php 56 | addTo(array('dwight@example.com', 'angela@example.com')); 61 | 62 | // You can either add one by one or pass an array to 'To' and 'CC' 63 | $m->addCC('holly@example.com'); 64 | $m->addCC(array('kelly@example.com', 'ryan@example.com')); 65 | 66 | // And 'BCC' and 'Reply-To' as well 67 | $m->addBCC('michael@example.com'); 68 | $m->addBCC(array('kevin@example.com', 'oscar@example.com')); 69 | $m->addReplyTo('andy@example.com'); 70 | $m->addReplyTo(array('stanley@example.com', 'erin@example.com')); 71 | 72 | 73 | // Also add names to any of the Recipients lists 74 | $m->addTo('Jim Carrey '); 75 | ``` 76 | 77 | ### Message body 78 | 79 | ```php 80 | setMessageFromFile('/path/to/some/file.txt'); 84 | $m->setMessageFromURL('http://example.com/somefile.txt'); 85 | 86 | // And have both Text and HTML version with: 87 | $m->setMessageFromString($text, $html); 88 | $m->setMessageFromFile($textfilepath, $htmlfilepath); 89 | $m->setMessageFromURL($texturl, $htmlurl); 90 | 91 | // Remember that setMessageFromString, setMessageFromFile, and setMessageFromURL are mutually exclusive. 92 | // If you call more than one, then whichever call you make last will be the message used. 93 | 94 | // You can also set the encoding of the Subject and the Message Body 95 | $m->setSubjectCharset('ISO-8859-1'); 96 | $m->setMessageCharset('ISO-8859-1'); 97 | ``` 98 | 99 | The default is UTF-8 if you do not specify a charset, which is usually the right setting. You can read more information in the [SES API documentation](http://docs.amazonwebservices.com/ses/latest/APIReference/API_Content.html) 100 | 101 | ### Attachments 102 | 103 | ```php 104 | addAttachmentFromData('my_text_file.txt', 'Simple content', 'text/plain'); 107 | $m->addAttachmentFromFile('my_PFD_file.pdf', '/path/to/pdf/file', 'application/pdf'); 108 | 109 | // SendRawEmail is explicitly used when there are attachments: 110 | $ses->sendEmail($m); 111 | // Sending raw email can be enforsed with: 112 | $ses->sendEmail($m, $use_raw_request = true); 113 | 114 | // Now you can add an inline file in the message 115 | $m->addAttachmentFromFile('logo.png','path/to/logo.png','application/octet-stream', '' , 'inline'); 116 | // and use it in the html version of the e-mail: 117 | ``` 118 | 119 | ### Configuration Set and Message Tags 120 | 121 | ```php 122 | setConfigurationSet('myConfigurationSet'); 126 | 127 | // Reset the configuration set 128 | $m->setConfigurationSet(null); 129 | 130 | 131 | // Set message tag 132 | $m->setMessageTag('key', 'value'); 133 | 134 | // Get message tag 135 | $tag = $m->getMessageTag('key'); 136 | 137 | // Remove message tag 138 | $m->removeMessageTag('key'); 139 | 140 | // Set message tags in bulk - performs merge with current tags 141 | $m->setMessageTags(array('key1' => 'value1', 'key2' => 'value2')); 142 | 143 | // Get message tags 144 | $tags = $m->getMessageTags(); 145 | 146 | // Remove all message tags 147 | $m->removeMessageTags(); 148 | ``` 149 | 150 | ### Sending Bulk Messages 151 | 152 | When hundreds of emails have to be sent in bulk it's best to use the Bulk mode which essentially reuses a CURL handler and reduces the number of SSL handshakes and this gives a better performance. 153 | 154 | ```php 155 | setBulkMode(true); 159 | 160 | // Send the messages 161 | foreach($messages as $message) { 162 | $ses->sendEmail($message); 163 | } 164 | 165 | // Disable bulk sending mode 166 | $ses->setBulkMode(false); 167 | ``` 168 | 169 | ### API Endpoints 170 | 171 | Few [Regions and Amazon SES endpoints](http://docs.aws.amazon.com/ses/latest/DeveloperGuide/regions.html) are available and they can be used like this: 172 | 173 | ```php 174 | listVerifiedEmailAddresses(); 187 | // Delete a verified address 188 | $ses->deleteVerifiedEmailAddress('user@example.com'); 189 | // Send a confirmation email in order to verify a new email 190 | $ses->verifyEmailAddress('user@example.com'); 191 | 192 | // Get Send Quota 193 | $ses->getSendQuota(); 194 | // Get Send Statistics 195 | $ses->getSendStatistics() 196 | ``` 197 | 198 | See the documentation on [GetSendQuota](http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendQuota.html) and [GetSendStatistics](http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendStatistics.html) for more information on these calls. 199 | 200 | ### Errors 201 | 202 | By default when Amazon SES API returns an error it will be triggered with [`trigger_error`](http://php.net/manual/en/function.trigger-error.php): 203 | 204 | ```php 205 | sendEmail($m, $use_raw_request, $trigger_error); 215 | ``` 216 | 217 | ### Request Signature Version 218 | 219 | You can configure which version of the request signature should be used. [Version 4](https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html) is now supported and used by default. 220 | 221 | ```php 222 | ` (#3) 294 | * Most of the notices should be cleared now (#5) 295 | 296 | v.0.8.3 297 | 298 | * Made automatic use of `SendRawEmail` REST API call when there are attachments 299 | 300 | v.0.8.2. 301 | 302 | * Inital impport 303 | 304 | ### Todo List 305 | 306 | * Fully document the class methods with phpdoc tags 307 | * Build documentation with phpDocumentor 308 | * Move examples to files 309 | * Make a [Composer](https://packagist.org/) package 310 | * Allow X-Headers usage 311 | 312 | ## Contributors 313 | 314 | ### Code Contributors 315 | 316 | This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. 317 | 318 | 319 | ### Financial Contributors 320 | 321 | Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/php-aws-ses/contribute)] 322 | 323 | #### Individuals 324 | 325 | 326 | 327 | #### Organizations 328 | 329 | Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/php-aws-ses/contribute)] 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | ### License 343 | 344 | MIT License 345 | 346 | Copyright (c) 2011 Dan Mayers 347 | Copyright (c) 2014 Daniel Zahariev 348 | 349 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 350 | 351 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 352 | 353 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 354 | -------------------------------------------------------------------------------- /README_old.md: -------------------------------------------------------------------------------- 1 | ### Old Documentation 2 | 3 | **** 4 | 5 | ### Example usages 6 | 7 | 8 | A bit of example code will be a good demonstration of how simple this class is to use. Please read through these examples, and then feel free leave a comment if you have any questions or suggestions. 9 | 10 | First, you’ll need to create a SimpleEmailService class object: 11 | 12 | require_once('ses.php'); 13 | $ses = new SimpleEmailService('Access Key Here', 'Secret Key Here'); 14 | 15 | If this is your first time using Simple Email Service, you will need to request verification of at least one e-mail address, so you can send messages: 16 | 17 | print_r($ses->verifyEmailAddress('user@example.com')); 18 | ------- 19 | Array 20 | ( 21 | [RequestId] => 1b086469-291d-11e0-85af-df1284f62f28 22 | ) 23 | 24 | Every request you make to SimpleEmailService will return a request id. This id may be useful if you need to contact AWS about any problems. For brevity, I will omit the request id if it is the only value returned from a service call. 25 | 26 | After you’ve requested verification, you’ll get an e-mail at that address with a link. Click the link to get your address approved. Once you’ve done that, you can use it as the ‘From’ address in the e-mails you send through SES. If you don’t have production access yet, you’ll also need to request verification for all addresses you want to send mail to. 27 | 28 | If you want to see what addresses have been verified on your account, it’s easy: 29 | 30 | print_r($ses->listVerifiedEmailAddresses()); 31 | ------- 32 | Array 33 | ( 34 | [RequestId] => 77128e89-291d-11e0-986f-43f07db0572a 35 | [Addresses] => Array 36 | ( 37 | [0] => user@example.com 38 | [1] => recipient@example.com 39 | ) 40 | ) 41 | 42 | Removing an address from the verified address list is just as easy: 43 | 44 | $ses->deleteVerifiedEmailAddress('user@example.com'); 45 | 46 | This call will return a request id if you need it. 47 | 48 | The only thing left to do is send an e-mail, so let’s try it. First, you’ll need a SimpleEmailServiceMessage object. Then, you’ll want to set various properties on the message. For example: 49 | 50 | $m = new SimpleEmailServiceMessage(); 51 | $m->addTo('recipient@example.com'); 52 | $m->setFrom('user@example.com'); 53 | $m->setSubject('Hello, world!'); 54 | $m->setMessageFromString('This is the message body.'); 55 | 56 | print_r($ses->sendEmail($m)); 57 | ------- 58 | Array 59 | ( 60 | [MessageId] => 0000012dc5e4b4c0-b2c566ad-dcd0-4d23-bea5-f40da774033c-000000 61 | [RequestId] => 4953a96e-29d4-11e0-8907-21df9ed6ffe3 62 | ) 63 | 64 | And that’s all there is to it! 65 | 66 | There are a few more things you can do with this class. You can make two informational queries, try these out: 67 | 68 | print_r($ses->getSendQuota()); 69 | print_r($ses->getSendStatistics()); 70 | 71 | For brevity I will not show the output of those two API calls. This information will help you keep track of the health of your account. See the Simple Email Service documentation on [GetSendQuota](http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendQuota.html) and [GetSendStatistics](http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendStatistics.html) for more information on these calls. 72 | 73 | You can set multiple to/cc/bcc addresses, either individually or all at once: 74 | 75 | $m->addTo('jim@example.com'); 76 | $m->addTo(array('dwight@example.com', 'angela@example.com')); 77 | $m->addCC('holly@example.com'); 78 | $m->addCC(array('kelly@example.com', 'ryan@example.com')); 79 | $m->addBCC('michael@example.com'); 80 | $m->addBCC(array('kevin@example.com', 'oscar@example.com')); 81 | 82 | These calls are cumulative, so in the above example, three addresses end up in each of the To, CC, and BCC fields. 83 | 84 | You can also set one or more Reply-To addresses: 85 | 86 | $m->addReplyTo('andy@example.com'); 87 | $m->addReplyTo(array('stanley@example.com', 'erin@example.com')); 88 | 89 | You can set a return path address: 90 | 91 | $m->setReturnPath('noreply@example.com'); 92 | 93 | You can use the contents of a file as the message text instead of a string: 94 | 95 | $m->setMessageFromFile('/path/to/some/file.txt'); 96 | // or from a URL, if allow_url_fopen is enabled: 97 | $m->setMessageFromURL('http://example.com/somefile.txt'); 98 | 99 | If you have both a text version and an HTML version of your message, you can set both: 100 | 101 | $m->setMessageFromString($text, $html); 102 | 103 | Or from a pair of files instead: 104 | 105 | $m->setMessageFromFile($textfilepath, $htmlfilepath); 106 | // or from a URL, if allow_url_fopen is enabled: 107 | $m->setMessageFromURL($texturl, $htmlurl); 108 | 109 | Remember that setMessageFromString, setMessageFromFile, and setMessageFromURL are mutually exclusive. If you call more than one, then whichever call you make last will be the message used. 110 | 111 | Finally, if you need to specify the character set used in the subject or message: 112 | 113 | $m->setSubjectCharset('ISO-8859-1'); 114 | $m->setMessageCharset('ISO-8859-1'); 115 | 116 | The default is UTF-8 if you do not specify a charset, which is usually the right setting. You can read more information in the [SES API documentation](http://docs.amazonwebservices.com/ses/latest/APIReference/API_Content.html). 117 | 118 | **** 119 | This library ~~does not support~~ **now supports** the `SendRawEmail` call, which means you ~~cannot~~ **can send emails with attachments** ~~or custom headers, and unfortunately I will be unable to add that support~~. 120 | 121 | The `SendRawEmail` call is used automatically when there are attachments: 122 | 123 | $m->addAttachmentFromData('my_text_file.txt', 'Simple content', 'text/plain'); 124 | $m->addAttachmentFromFile('my_PFD_file.pdf', '/path/to/pdf/file', 'application/pdf'); 125 | // SendRawEmail call will now be used: 126 | $ses->sendEmail($m); 127 | 128 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.9.3 2 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "daniel-zahariev/php-aws-ses", 3 | "description": "Send emails via Amazon Simple Email Service (SES) with REST-like interface", 4 | "keywords": ["amazon", "email","aws","ses", "api", "rest"], 5 | "homepage": "https://github.com/daniel-zahariev/php-aws-ses", 6 | "type": "library", 7 | "license": "MIT", 8 | "minimum-stability": "stable", 9 | "prefer-stable": true, 10 | "authors": [ 11 | { 12 | "name": "Daniel Zahariev", 13 | "role": "developer" 14 | } 15 | ], 16 | "autoload": { 17 | "classmap": ["src/"] 18 | }, 19 | "require": { 20 | "php": ">=5.0.0", 21 | "ext-curl": "*", 22 | "ext-simplexml": "*" 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "^7.1", 26 | "phpunit/php-code-coverage": "^6.0", 27 | "fzaninotto/faker": "^1.7", 28 | "phpspec/prophecy": "~1.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | ./tests 21 | 22 | 23 | 24 | 25 | ./src 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/SimpleEmailService.php: -------------------------------------------------------------------------------- 1 | setAuth($accessKey, $secretKey); 138 | } 139 | $this->__host = $host; 140 | $this->__trigger_errors = $trigger_errors; 141 | $this->__requestSignatureVersion = $requestSignatureVersion; 142 | } 143 | 144 | /** 145 | * Set the request signature version 146 | * 147 | * @param string $requestSignatureVersion Value is ignored and V4 is used. This for BW compatibility. 148 | * @return SimpleEmailService $this 149 | * 150 | * @deprecated Currently only V4 supported. 151 | */ 152 | public function setRequestSignatureVersion($requestSignatureVersion) { 153 | $this->__requestSignatureVersion = $requestSignatureVersion; 154 | 155 | return $this; 156 | } 157 | 158 | /** 159 | * @return string 160 | * 161 | * @deprecated Not relevant when only V4 is supported. 162 | */ 163 | public function getRequestSignatureVersion() { 164 | return $this->__requestSignatureVersion; 165 | } 166 | 167 | /** 168 | * Set AWS access key and secret key 169 | * 170 | * @param string $accessKey Access key 171 | * @param string $secretKey Secret key 172 | * @return SimpleEmailService $this 173 | */ 174 | public function setAuth($accessKey, $secretKey) { 175 | $this->__accessKey = $accessKey; 176 | $this->__secretKey = $secretKey; 177 | 178 | return $this; 179 | } 180 | 181 | /** 182 | * Set AWS Host 183 | * @param string $host AWS Host 184 | */ 185 | public function setHost($host = self::AWS_US_EAST_1) { 186 | $this->__host = $host; 187 | 188 | return $this; 189 | } 190 | 191 | /** 192 | * @deprecated 193 | */ 194 | public function enableVerifyHost($enable = true) { 195 | $this->__verifyHost = (bool)$enable; 196 | 197 | return $this; 198 | } 199 | 200 | /** 201 | * @deprecated 202 | */ 203 | public function enableVerifyPeer($enable = true) { 204 | $this->__verifyPeer = (bool)$enable; 205 | 206 | return $this; 207 | } 208 | 209 | /** 210 | * @deprecated 211 | */ 212 | public function verifyHost() { 213 | return $this->__verifyHost; 214 | } 215 | 216 | /** 217 | * @deprecated 218 | */ 219 | public function verifyPeer() { 220 | return $this->__verifyPeer; 221 | } 222 | 223 | 224 | /** 225 | * Get AWS target host 226 | * @return boolean 227 | */ 228 | public function getHost() { 229 | return $this->__host; 230 | } 231 | 232 | /** 233 | * Get AWS SES auth access key 234 | * @return string 235 | */ 236 | public function getAccessKey() { 237 | return $this->__accessKey; 238 | } 239 | 240 | /** 241 | * Get AWS SES auth secret key 242 | * @return string 243 | */ 244 | public function getSecretKey() { 245 | return $this->__secretKey; 246 | } 247 | 248 | /** 249 | * Get the verify peer CURL mode 250 | * @return boolean 251 | */ 252 | public function getVerifyPeer() { 253 | return $this->__verifyPeer; 254 | } 255 | 256 | /** 257 | * Get the verify host CURL mode 258 | * @return boolean 259 | */ 260 | public function getVerifyHost() { 261 | return $this->__verifyHost; 262 | } 263 | 264 | /** 265 | * Get bulk email sending mode 266 | * @deprecated 267 | * @return boolean 268 | */ 269 | public function getBulkMode() { 270 | return $this->__bulk_sending_mode; 271 | } 272 | 273 | 274 | /** 275 | * Enable/disable CURLOPT_SSL_VERIFYHOST for SimpleEmailServiceRequest's curl handler 276 | * verifyHost and verifyPeer determine whether curl verifies ssl certificates. 277 | * It may be necessary to disable these checks on certain systems. 278 | * These only have an effect if SSL is enabled. 279 | * 280 | * @param boolean $enable New status for the mode 281 | * @return SimpleEmailService $this 282 | */ 283 | public function setVerifyHost($enable = true) { 284 | $this->__verifyHost = (bool)$enable; 285 | return $this; 286 | } 287 | 288 | /** 289 | * Enable/disable CURLOPT_SSL_VERIFYPEER for SimpleEmailServiceRequest's curl handler 290 | * verifyHost and verifyPeer determine whether curl verifies ssl certificates. 291 | * It may be necessary to disable these checks on certain systems. 292 | * These only have an effect if SSL is enabled. 293 | * 294 | * @param boolean $enable New status for the mode 295 | * @return SimpleEmailService $this 296 | */ 297 | public function setVerifyPeer($enable = true) { 298 | $this->__verifyPeer = (bool)$enable; 299 | return $this; 300 | } 301 | 302 | /** 303 | * Enable/disable bulk email sending mode 304 | * 305 | * @param boolean $enable New status for the mode 306 | * @return SimpleEmailService $this 307 | * @deprecated 308 | */ 309 | public function setBulkMode($enable = true) { 310 | $this->__bulk_sending_mode = (bool)$enable; 311 | return $this; 312 | } 313 | 314 | /** 315 | * Lists the email addresses that have been verified and can be used as the 'From' address 316 | * 317 | * @return array An array containing two items: a list of verified email addresses, and the request id. 318 | */ 319 | public function listVerifiedEmailAddresses() { 320 | $ses_request = $this->getRequestHandler('GET'); 321 | $ses_request->setParameter('Action', 'ListVerifiedEmailAddresses'); 322 | 323 | $ses_response = $ses_request->getResponse(); 324 | if($ses_response->error === false && $ses_response->code !== 200) { 325 | $ses_response->error = array('code' => $ses_response->code, 'message' => 'Unexpected HTTP status'); 326 | } 327 | if($ses_response->error !== false) { 328 | $this->__triggerError('listVerifiedEmailAddresses', $ses_response->error); 329 | return false; 330 | } 331 | 332 | $response = array(); 333 | if(!isset($ses_response->body)) { 334 | return $response; 335 | } 336 | 337 | $addresses = array(); 338 | foreach($ses_response->body->ListVerifiedEmailAddressesResult->VerifiedEmailAddresses->member as $address) { 339 | $addresses[] = (string)$address; 340 | } 341 | 342 | $response['Addresses'] = $addresses; 343 | $response['RequestId'] = (string)$ses_response->body->ResponseMetadata->RequestId; 344 | 345 | return $response; 346 | } 347 | 348 | /** 349 | * Requests verification of the provided email address, so it can be used 350 | * as the 'From' address when sending emails through SimpleEmailService. 351 | * 352 | * After submitting this request, you should receive a verification email 353 | * from Amazon at the specified address containing instructions to follow. 354 | * 355 | * @param string $email The email address to get verified 356 | * @return array The request id for this request. 357 | */ 358 | public function verifyEmailAddress($email) { 359 | $ses_request = $this->getRequestHandler('POST'); 360 | $ses_request->setParameter('Action', 'VerifyEmailAddress'); 361 | $ses_request->setParameter('EmailAddress', $email); 362 | 363 | $ses_response = $ses_request->getResponse(); 364 | if($ses_response->error === false && $ses_response->code !== 200) { 365 | $ses_response->error = array('code' => $ses_response->code, 'message' => 'Unexpected HTTP status'); 366 | } 367 | if($ses_response->error !== false) { 368 | $this->__triggerError('verifyEmailAddress', $ses_response->error); 369 | return false; 370 | } 371 | 372 | $response['RequestId'] = (string)$ses_response->body->ResponseMetadata->RequestId; 373 | return $response; 374 | } 375 | 376 | /** 377 | * Removes the specified email address from the list of verified addresses. 378 | * 379 | * @param string $email The email address to remove 380 | * @return array The request id for this request. 381 | */ 382 | public function deleteVerifiedEmailAddress($email) { 383 | $ses_request = $this->getRequestHandler('DELETE'); 384 | $ses_request->setParameter('Action', 'DeleteVerifiedEmailAddress'); 385 | $ses_request->setParameter('EmailAddress', $email); 386 | 387 | $ses_response = $ses_request->getResponse(); 388 | if($ses_response->error === false && $ses_response->code !== 200) { 389 | $ses_response->error = array('code' => $ses_response->code, 'message' => 'Unexpected HTTP status'); 390 | } 391 | if($ses_response->error !== false) { 392 | $this->__triggerError('deleteVerifiedEmailAddress', $ses_response->error); 393 | return false; 394 | } 395 | 396 | $response['RequestId'] = (string)$ses_response->body->ResponseMetadata->RequestId; 397 | return $response; 398 | } 399 | 400 | /** 401 | * Retrieves information on the current activity limits for this account. 402 | * See http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendQuota.html 403 | * 404 | * @return array An array containing information on this account's activity limits. 405 | */ 406 | public function getSendQuota() { 407 | $ses_request = $this->getRequestHandler('GET'); 408 | $ses_request->setParameter('Action', 'GetSendQuota'); 409 | 410 | $ses_response = $ses_request->getResponse(); 411 | if($ses_response->error === false && $ses_response->code !== 200) { 412 | $ses_response->error = array('code' => $ses_response->code, 'message' => 'Unexpected HTTP status'); 413 | } 414 | if($ses_response->error !== false) { 415 | $this->__triggerError('getSendQuota', $ses_response->error); 416 | return false; 417 | } 418 | 419 | $response = array(); 420 | if(!isset($ses_response->body)) { 421 | return $response; 422 | } 423 | 424 | $response['Max24HourSend'] = (string)$ses_response->body->GetSendQuotaResult->Max24HourSend; 425 | $response['MaxSendRate'] = (string)$ses_response->body->GetSendQuotaResult->MaxSendRate; 426 | $response['SentLast24Hours'] = (string)$ses_response->body->GetSendQuotaResult->SentLast24Hours; 427 | $response['RequestId'] = (string)$ses_response->body->ResponseMetadata->RequestId; 428 | 429 | return $response; 430 | } 431 | 432 | /** 433 | * Retrieves statistics for the last two weeks of activity on this account. 434 | * See http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendStatistics.html 435 | * 436 | * @return array An array of activity statistics. Each array item covers a 15-minute period. 437 | */ 438 | public function getSendStatistics() { 439 | $ses_request = $this->getRequestHandler('GET'); 440 | $ses_request->setParameter('Action', 'GetSendStatistics'); 441 | 442 | $ses_response = $ses_request->getResponse(); 443 | if($ses_response->error === false && $ses_response->code !== 200) { 444 | $ses_response->error = array('code' => $ses_response->code, 'message' => 'Unexpected HTTP status'); 445 | } 446 | if($ses_response->error !== false) { 447 | $this->__triggerError('getSendStatistics', $ses_response->error); 448 | return false; 449 | } 450 | 451 | $response = array(); 452 | if(!isset($ses_response->body)) { 453 | return $response; 454 | } 455 | 456 | $datapoints = array(); 457 | foreach($ses_response->body->GetSendStatisticsResult->SendDataPoints->member as $datapoint) { 458 | $p = array(); 459 | $p['Bounces'] = (string)$datapoint->Bounces; 460 | $p['Complaints'] = (string)$datapoint->Complaints; 461 | $p['DeliveryAttempts'] = (string)$datapoint->DeliveryAttempts; 462 | $p['Rejects'] = (string)$datapoint->Rejects; 463 | $p['Timestamp'] = (string)$datapoint->Timestamp; 464 | 465 | $datapoints[] = $p; 466 | } 467 | 468 | $response['SendDataPoints'] = $datapoints; 469 | $response['RequestId'] = (string)$ses_response->body->ResponseMetadata->RequestId; 470 | 471 | return $response; 472 | } 473 | 474 | 475 | /** 476 | * Given a SimpleEmailServiceMessage object, submits the message to the service for sending. 477 | * 478 | * @param SimpleEmailServiceMessage $sesMessage An instance of the message class 479 | * @param boolean $use_raw_request If this is true or there are attachments to the email `SendRawEmail` call will be used 480 | * @param boolean $trigger_error Optionally overwrite the class setting for triggering an error (with type check to true/false) 481 | * @return array An array containing the unique identifier for this message and a separate request id. 482 | * Returns false if the provided message is missing any required fields. 483 | * @link(AWS SES Response formats, http://docs.aws.amazon.com/ses/latest/DeveloperGuide/query-interface-responses.html) 484 | */ 485 | public function sendEmail($sesMessage, $use_raw_request = false , $trigger_error = null) { 486 | if(!$sesMessage->validate()) { 487 | $this->__triggerError('sendEmail', 'Message failed validation.'); 488 | return false; 489 | } 490 | 491 | $ses_request = $this->getRequestHandler('POST'); 492 | $action = !empty($sesMessage->attachments) || $use_raw_request ? 'SendRawEmail' : 'SendEmail'; 493 | $ses_request->setParameter('Action', $action); 494 | 495 | // Works with both calls 496 | if (!is_null($sesMessage->configuration_set)) { 497 | $ses_request->setParameter('ConfigurationSetName', $sesMessage->configuration_set); 498 | } 499 | 500 | if($action == 'SendRawEmail') { 501 | // https://docs.aws.amazon.com/ses/latest/APIReference/API_SendRawEmail.html 502 | $ses_request->setParameter('RawMessage.Data', $sesMessage->getRawMessage()); 503 | } else { 504 | $i = 1; 505 | foreach($sesMessage->to as $to) { 506 | $ses_request->setParameter('Destination.ToAddresses.member.'.$i, $sesMessage->encodeRecipients($to)); 507 | $i++; 508 | } 509 | 510 | if(is_array($sesMessage->cc)) { 511 | $i = 1; 512 | foreach($sesMessage->cc as $cc) { 513 | $ses_request->setParameter('Destination.CcAddresses.member.'.$i, $sesMessage->encodeRecipients($cc)); 514 | $i++; 515 | } 516 | } 517 | 518 | if(is_array($sesMessage->bcc)) { 519 | $i = 1; 520 | foreach($sesMessage->bcc as $bcc) { 521 | $ses_request->setParameter('Destination.BccAddresses.member.'.$i, $sesMessage->encodeRecipients($bcc)); 522 | $i++; 523 | } 524 | } 525 | 526 | if(is_array($sesMessage->replyto)) { 527 | $i = 1; 528 | foreach($sesMessage->replyto as $replyto) { 529 | $ses_request->setParameter('ReplyToAddresses.member.'.$i, $sesMessage->encodeRecipients($replyto)); 530 | $i++; 531 | } 532 | } 533 | 534 | $ses_request->setParameter('Source', $sesMessage->encodeRecipients($sesMessage->from)); 535 | 536 | if($sesMessage->returnpath != null) { 537 | $ses_request->setParameter('ReturnPath', $sesMessage->returnpath); 538 | } 539 | 540 | if($sesMessage->subject != null && strlen($sesMessage->subject) > 0) { 541 | $ses_request->setParameter('Message.Subject.Data', $sesMessage->subject); 542 | if($sesMessage->subjectCharset != null && strlen($sesMessage->subjectCharset) > 0) { 543 | $ses_request->setParameter('Message.Subject.Charset', $sesMessage->subjectCharset); 544 | } 545 | } 546 | 547 | 548 | if($sesMessage->messagetext != null && strlen($sesMessage->messagetext) > 0) { 549 | $ses_request->setParameter('Message.Body.Text.Data', $sesMessage->messagetext); 550 | if($sesMessage->messageTextCharset != null && strlen($sesMessage->messageTextCharset) > 0) { 551 | $ses_request->setParameter('Message.Body.Text.Charset', $sesMessage->messageTextCharset); 552 | } 553 | } 554 | 555 | if($sesMessage->messagehtml != null && strlen($sesMessage->messagehtml) > 0) { 556 | $ses_request->setParameter('Message.Body.Html.Data', $sesMessage->messagehtml); 557 | if($sesMessage->messageHtmlCharset != null && strlen($sesMessage->messageHtmlCharset) > 0) { 558 | $ses_request->setParameter('Message.Body.Html.Charset', $sesMessage->messageHtmlCharset); 559 | } 560 | } 561 | 562 | $i = 1; 563 | foreach($sesMessage->message_tags as $key => $value) { 564 | $ses_request->setParameter('Tags.member.'.$i.'.Name', $key); 565 | $ses_request->setParameter('Tags.member.'.$i.'.Value', $value); 566 | $i++; 567 | } 568 | } 569 | 570 | $ses_response = $ses_request->getResponse(); 571 | if($ses_response->error === false && $ses_response->code !== 200) { 572 | $response = array( 573 | 'code' => $ses_response->code, 574 | 'error' => array('Error' => array('message' => 'Unexpected HTTP status')), 575 | ); 576 | return $response; 577 | } 578 | if($ses_response->error !== false) { 579 | if (($this->__trigger_errors && ($trigger_error !== false)) || $trigger_error === true) { 580 | $this->__triggerError('sendEmail', $ses_response->error); 581 | return false; 582 | } 583 | return $ses_response; 584 | } 585 | 586 | $response = array( 587 | 'MessageId' => (string)$ses_response->body->{"{$action}Result"}->MessageId, 588 | 'RequestId' => (string)$ses_response->body->ResponseMetadata->RequestId, 589 | ); 590 | return $response; 591 | } 592 | 593 | /** 594 | * Trigger an error message 595 | * 596 | * {@internal Used by member functions to output errors} 597 | * @param string $functionname The name of the function that failed 598 | * @param array $error Array containing error information 599 | * @return void 600 | */ 601 | public function __triggerError($functionname, $error) 602 | { 603 | if($error == false) { 604 | trigger_error(sprintf("SimpleEmailService::%s(): Encountered an error, but no description given", $functionname), E_USER_WARNING); 605 | } 606 | else if(isset($error['curl']) && $error['curl']) 607 | { 608 | trigger_error(sprintf("SimpleEmailService::%s(): %s %s", $functionname, $error['code'], $error['message']), E_USER_WARNING); 609 | } 610 | else if(isset($error['Error'])) 611 | { 612 | $e = $error['Error']; 613 | $message = sprintf("SimpleEmailService::%s(): %s - %s: %s\nRequest Id: %s\n", $functionname, $e['Type'], $e['Code'], $e['Message'], $error['RequestId']); 614 | trigger_error($message, E_USER_WARNING); 615 | } 616 | else { 617 | trigger_error(sprintf("SimpleEmailService::%s(): Encountered an error: %s", $functionname, $error), E_USER_WARNING); 618 | } 619 | } 620 | 621 | /** 622 | * Set SES Request 623 | * 624 | * @param SimpleEmailServiceRequest $ses_request description 625 | * @return SimpleEmailService $this 626 | */ 627 | public function setRequestHandler(SimpleEmailServiceRequest $ses_request = null) { 628 | if (!is_null($ses_request)) { 629 | $ses_request->setSES($this); 630 | } 631 | 632 | $this->__ses_request = $ses_request; 633 | 634 | return $this; 635 | } 636 | 637 | /** 638 | * Get SES Request 639 | * 640 | * @param string $verb HTTP Verb: GET, POST, DELETE 641 | * @return SimpleEmailServiceRequest SES Request 642 | */ 643 | public function getRequestHandler($verb) { 644 | if (empty($this->__ses_request)) { 645 | $this->__ses_request = new SimpleEmailServiceRequest($this, $verb); 646 | } else { 647 | $this->__ses_request->setVerb($verb); 648 | } 649 | 650 | return $this->__ses_request; 651 | } 652 | } 653 | -------------------------------------------------------------------------------- /src/SimpleEmailServiceMessage.php: -------------------------------------------------------------------------------- 1 | to = array(); 22 | $this->cc = array(); 23 | $this->bcc = array(); 24 | $this->replyto = array(); 25 | $this->recipientsCharset = 'UTF-8'; 26 | 27 | $this->from = null; 28 | $this->returnpath = null; 29 | 30 | $this->subject = null; 31 | $this->messagetext = null; 32 | $this->messagehtml = null; 33 | 34 | $this->subjectCharset = 'UTF-8'; 35 | $this->messageTextCharset = 'UTF-8'; 36 | $this->messageHtmlCharset = 'UTF-8'; 37 | 38 | $this->attachments = array(); 39 | $this->customHeaders = array(); 40 | $this->configuration_set = null; 41 | $this->message_tags = array(); 42 | 43 | $this->is_clean = true; 44 | $this->raw_message = null; 45 | } 46 | 47 | /** 48 | * addTo, addCC, addBCC, and addReplyTo have the following behavior: 49 | * If a single address is passed, it is appended to the current list of addresses. 50 | * If an array of addresses is passed, that array is merged into the current list. 51 | * 52 | * @return SimpleEmailServiceMessage $this 53 | * @link http://docs.aws.amazon.com/ses/latest/APIReference/API_Destination.html 54 | */ 55 | public function addTo($to) { 56 | if (!is_array($to)) { 57 | $this->to[] = $to; 58 | } else { 59 | $this->to = array_unique(array_merge($this->to, $to)); 60 | } 61 | 62 | $this->is_clean = false; 63 | 64 | return $this; 65 | } 66 | 67 | /** 68 | * @return SimpleEmailServiceMessage $this 69 | */ 70 | public function setTo($to) { 71 | $this->to = (array) $to; 72 | 73 | $this->is_clean = false; 74 | 75 | return $this; 76 | } 77 | 78 | /** 79 | * Clear the To: email address(es) for the message 80 | * 81 | * @return SimpleEmailServiceMessage $this 82 | */ 83 | public function clearTo() { 84 | $this->to = array(); 85 | 86 | $this->is_clean = false; 87 | 88 | return $this; 89 | } 90 | 91 | /** 92 | * @return SimpleEmailServiceMessage $this 93 | * @see addTo() 94 | */ 95 | public function addCC($cc) { 96 | if (!is_array($cc)) { 97 | $this->cc[] = $cc; 98 | } else { 99 | $this->cc = array_merge($this->cc, $cc); 100 | } 101 | 102 | $this->is_clean = false; 103 | 104 | return $this; 105 | } 106 | 107 | /** 108 | * Clear the CC: email address(es) for the message 109 | * 110 | * @return SimpleEmailServiceMessage $this 111 | */ 112 | public function clearCC() { 113 | $this->cc = array(); 114 | 115 | $this->is_clean = false; 116 | 117 | return $this; 118 | } 119 | 120 | /** 121 | * @return SimpleEmailServiceMessage $this 122 | * @see addTo() 123 | */ 124 | public function addBCC($bcc) { 125 | if (!is_array($bcc)) { 126 | $this->bcc[] = $bcc; 127 | } else { 128 | $this->bcc = array_merge($this->bcc, $bcc); 129 | } 130 | 131 | $this->is_clean = false; 132 | 133 | return $this; 134 | } 135 | 136 | /** 137 | * Clear the BCC: email address(es) for the message 138 | * 139 | * @return SimpleEmailServiceMessage $this 140 | */ 141 | public function clearBCC() { 142 | $this->bcc = array(); 143 | 144 | $this->is_clean = false; 145 | 146 | return $this; 147 | } 148 | 149 | /** 150 | * @return SimpleEmailServiceMessage $this 151 | * @see addTo() 152 | */ 153 | public function addReplyTo($replyto) { 154 | if (!is_array($replyto)) { 155 | $this->replyto[] = $replyto; 156 | } else { 157 | $this->replyto = array_merge($this->replyto, $replyto); 158 | } 159 | 160 | $this->is_clean = false; 161 | 162 | return $this; 163 | } 164 | 165 | /** 166 | * Clear the Reply-To: email address(es) for the message 167 | * 168 | * @return SimpleEmailServiceMessage $this 169 | */ 170 | public function clearReplyTo() { 171 | $this->replyto = array(); 172 | 173 | $this->is_clean = false; 174 | 175 | return $this; 176 | } 177 | 178 | /** 179 | * Clear all of the message recipients in one go 180 | * 181 | * @return SimpleEmailServiceMessage $this 182 | * @uses clearTo() 183 | * @uses clearCC() 184 | * @uses clearBCC() 185 | * @uses clearReplyTo() 186 | */ 187 | public function clearRecipients() { 188 | $this->clearTo(); 189 | $this->clearCC(); 190 | $this->clearBCC(); 191 | $this->clearReplyTo(); 192 | 193 | $this->is_clean = false; 194 | 195 | return $this; 196 | } 197 | 198 | /** 199 | * @return SimpleEmailServiceMessage $this 200 | */ 201 | public function setFrom($from) { 202 | $this->from = $from; 203 | 204 | $this->is_clean = false; 205 | 206 | return $this; 207 | } 208 | 209 | /** 210 | * @return SimpleEmailServiceMessage $this 211 | */ 212 | public function setReturnPath($returnpath) { 213 | $this->returnpath = $returnpath; 214 | 215 | $this->is_clean = false; 216 | 217 | return $this; 218 | } 219 | 220 | /** 221 | * @return SimpleEmailServiceMessage $this 222 | */ 223 | public function setRecipientsCharset($charset) { 224 | $this->recipientsCharset = $charset; 225 | 226 | $this->is_clean = false; 227 | 228 | return $this; 229 | } 230 | 231 | /** 232 | * @return SimpleEmailServiceMessage $this 233 | */ 234 | public function setSubject($subject) { 235 | $this->subject = $subject; 236 | 237 | $this->is_clean = false; 238 | 239 | return $this; 240 | } 241 | 242 | /** 243 | * @return SimpleEmailServiceMessage $this 244 | */ 245 | public function setSubjectCharset($charset) { 246 | $this->subjectCharset = $charset; 247 | 248 | $this->is_clean = false; 249 | 250 | return $this; 251 | } 252 | 253 | /** 254 | * @return SimpleEmailServiceMessage $this 255 | * @link http://docs.aws.amazon.com/ses/latest/APIReference/API_Message.html 256 | */ 257 | public function setMessageFromString($text, $html = null) { 258 | $this->messagetext = $text; 259 | $this->messagehtml = $html; 260 | 261 | $this->is_clean = false; 262 | 263 | return $this; 264 | } 265 | 266 | /** 267 | * @return SimpleEmailServiceMessage $this 268 | */ 269 | public function setMessageFromFile($textfile, $htmlfile = null) { 270 | if (file_exists($textfile) && is_file($textfile) && is_readable($textfile)) { 271 | $this->messagetext = file_get_contents($textfile); 272 | } else { 273 | $this->messagetext = null; 274 | } 275 | if (file_exists($htmlfile) && is_file($htmlfile) && is_readable($htmlfile)) { 276 | $this->messagehtml = file_get_contents($htmlfile); 277 | } else { 278 | $this->messagehtml = null; 279 | } 280 | 281 | $this->is_clean = false; 282 | 283 | return $this; 284 | } 285 | 286 | /** 287 | * @return SimpleEmailServiceMessage $this 288 | */ 289 | public function setMessageFromURL($texturl, $htmlurl = null) { 290 | if ($texturl !== null) { 291 | $this->messagetext = file_get_contents($texturl); 292 | } else { 293 | $this->messagetext = null; 294 | } 295 | if ($htmlurl !== null) { 296 | $this->messagehtml = file_get_contents($htmlurl); 297 | } else { 298 | $this->messagehtml = null; 299 | } 300 | 301 | $this->is_clean = false; 302 | 303 | return $this; 304 | } 305 | 306 | /** 307 | * @return SimpleEmailServiceMessage $this 308 | */ 309 | public function setMessageCharset($textCharset, $htmlCharset = null) { 310 | $this->messageTextCharset = $textCharset; 311 | $this->messageHtmlCharset = $htmlCharset; 312 | 313 | $this->is_clean = false; 314 | 315 | return $this; 316 | } 317 | 318 | /** 319 | * @return SimpleEmailServiceMessage $this 320 | */ 321 | public function setConfigurationSet($configuration_set = null) { 322 | $this->configuration_set = $configuration_set; 323 | 324 | $this->is_clean = false; 325 | 326 | return $this; 327 | } 328 | 329 | /** 330 | * @return array $message_tags 331 | */ 332 | public function getMessageTags() { 333 | return $this->message_tags; 334 | } 335 | 336 | /** 337 | * @return null|mixed $message_tag 338 | */ 339 | public function getMessageTag($key) { 340 | return isset($this->message_tags[$key]) ? $this->message_tags[$key] : null; 341 | } 342 | 343 | /** 344 | * Add Message tag 345 | * 346 | * Both key and value can contain only ASCII letters (a-z, A-Z), numbers (0-9), underscores (_), or dashes (-) and be less than 256 characters. 347 | * 348 | * @param string $key 349 | * @param mixed $value 350 | * @return SimpleEmailServiceMessage $this 351 | * @link https://docs.aws.amazon.com/ses/latest/DeveloperGuide/event-publishing-send-email.html 352 | * @link https://docs.aws.amazon.com/ses/latest/APIReference/API_MessageTag.html 353 | */ 354 | public function setMessageTag($key, $value) { 355 | $this->message_tags[$key] = $value; 356 | 357 | $this->is_clean = false; 358 | 359 | return $this; 360 | } 361 | 362 | /** 363 | * @param string $key The key of the tag to be removed 364 | * @return SimpleEmailServiceMessage $this 365 | */ 366 | public function removeMessageTag($key) { 367 | unset($this->message_tags[$key]); 368 | 369 | $this->is_clean = false; 370 | 371 | return $this; 372 | } 373 | 374 | /** 375 | * @param array $message_tags 376 | * @return SimpleEmailServiceMessage $this 377 | */ 378 | public function setMessageTags($message_tags = array()) { 379 | $this->message_tags = array_merge($this->message_tags, $message_tags); 380 | 381 | $this->is_clean = false; 382 | 383 | return $this; 384 | } 385 | 386 | /** 387 | * @return SimpleEmailServiceMessage $this 388 | */ 389 | public function removeMessageTags() { 390 | $this->message_tags = array(); 391 | 392 | $this->is_clean = false; 393 | 394 | return $this; 395 | } 396 | 397 | /** 398 | * Add custom header - this works only with SendRawEmail 399 | * 400 | * @param string $header Your custom header 401 | * @return SimpleEmailServiceMessage $this 402 | * @link( Restrictions on headers, http://docs.aws.amazon.com/ses/latest/DeveloperGuide/header-fields.html) 403 | */ 404 | public function addCustomHeader($header) { 405 | $this->customHeaders[] = $header; 406 | 407 | $this->is_clean = false; 408 | 409 | return $this; 410 | } 411 | 412 | /** 413 | * Add email attachment by directly passing the content 414 | * 415 | * @param string $name The name of the file attachment as it will appear in the email 416 | * @param string $data The contents of the attachment file 417 | * @param string $mimeType Specify custom MIME type 418 | * @param string $contentId Content ID of the attachment for inclusion in the mail message 419 | * @param string $attachmentType Attachment type: attachment or inline 420 | * @return SimpleEmailServiceMessage $this 421 | */ 422 | public function addAttachmentFromData($name, $data, $mimeType = 'application/octet-stream', $contentId = null, $attachmentType = 'attachment') { 423 | $this->attachments[$name] = array( 424 | 'name' => $name, 425 | 'mimeType' => $mimeType, 426 | 'data' => $data, 427 | 'contentId' => $contentId, 428 | 'attachmentType' => ($attachmentType == 'inline' ? 'inline; filename="' . $name . '"' : $attachmentType), 429 | ); 430 | 431 | $this->is_clean = false; 432 | 433 | return $this; 434 | } 435 | 436 | /** 437 | * Add email attachment by passing file path 438 | * 439 | * @param string $name The name of the file attachment as it will appear in the email 440 | * @param string $path Path to the attachment file 441 | * @param string $mimeType Specify custom MIME type 442 | * @param string $contentId Content ID of the attachment for inclusion in the mail message 443 | * @param string $attachmentType Attachment type: attachment or inline 444 | * @return boolean Status of the operation 445 | */ 446 | public function addAttachmentFromFile($name, $path, $mimeType = 'application/octet-stream', $contentId = null, $attachmentType = 'attachment') { 447 | if (file_exists($path) && is_file($path) && is_readable($path)) { 448 | $this->addAttachmentFromData($name, file_get_contents($path), $mimeType, $contentId, $attachmentType); 449 | return true; 450 | } 451 | 452 | $this->is_clean = false; 453 | 454 | return false; 455 | } 456 | 457 | /** 458 | * Add email attachment by passing file path 459 | * 460 | * @param string $name The name of the file attachment as it will appear in the email 461 | * @param string $url URL to the attachment file 462 | * @param string $mimeType Specify custom MIME type 463 | * @param string $contentId Content ID of the attachment for inclusion in the mail message 464 | * @param string $attachmentType Attachment type: attachment or inline 465 | * @return boolean Status of the operation 466 | */ 467 | public function addAttachmentFromUrl($name, $url, $mimeType = 'application/octet-stream', $contentId = null, $attachmentType = 'attachment') { 468 | $data = file_get_contents($url); 469 | if ($data !== false) { 470 | $this->addAttachmentFromData($name, $data, $mimeType, $contentId, $attachmentType); 471 | return true; 472 | } 473 | 474 | $this->is_clean = false; 475 | 476 | return false; 477 | } 478 | 479 | /** 480 | * Get the existence of attached inline messages 481 | * 482 | * @return boolean 483 | */ 484 | public function hasInlineAttachments() { 485 | foreach ($this->attachments as $attachment) { 486 | if ($attachment['attachmentType'] != 'attachment') { 487 | return true; 488 | } 489 | 490 | } 491 | return false; 492 | } 493 | 494 | /** 495 | * Get the raw mail message 496 | * 497 | * @return string 498 | */ 499 | public function getRawMessage($encode = true) { 500 | if ($this->is_clean && !is_null($this->raw_message) && $encode) { 501 | return $this->raw_message; 502 | } 503 | 504 | $this->is_clean = true; 505 | 506 | $boundary = uniqid(rand(), true); 507 | $raw_message = count($this->customHeaders) > 0 ? join("\n", $this->customHeaders) . "\n" : ''; 508 | 509 | if (!empty($this->message_tags)) { 510 | $message_tags = array(); 511 | foreach ($this->message_tags as $key => $value) { 512 | $message_tags[] = "{$key}={$value}"; 513 | } 514 | 515 | $raw_message .= 'X-SES-MESSAGE-TAGS: ' . join(', ', $message_tags) . "\n"; 516 | } 517 | 518 | if (!is_null($this->configuration_set)) { 519 | $raw_message .= 'X-SES-CONFIGURATION-SET: ' . $this->configuration_set . "\n"; 520 | } 521 | 522 | $raw_message .= count($this->to) > 0 ? 'To: ' . $this->encodeRecipients($this->to) . "\n" : ''; 523 | $raw_message .= 'From: ' . $this->encodeRecipients($this->from) . "\n"; 524 | if (!empty($this->replyto)) { 525 | $raw_message .= 'Reply-To: ' . $this->encodeRecipients($this->replyto) . "\n"; 526 | } 527 | 528 | if (!empty($this->cc)) { 529 | $raw_message .= 'CC: ' . $this->encodeRecipients($this->cc) . "\n"; 530 | } 531 | if (!empty($this->bcc)) { 532 | $raw_message .= 'BCC: ' . $this->encodeRecipients($this->bcc) . "\n"; 533 | } 534 | 535 | if ($this->subject != null && strlen($this->subject) > 0) { 536 | $raw_message .= 'Subject: =?' . $this->subjectCharset . '?B?' . base64_encode($this->subject) . "?=\n"; 537 | } 538 | 539 | $raw_message .= 'MIME-Version: 1.0' . "\n"; 540 | $raw_message .= 'Content-type: ' . ($this->hasInlineAttachments() ? 'multipart/related' : 'Multipart/Mixed') . '; boundary="' . $boundary . '"' . "\n"; 541 | $raw_message .= "\n--{$boundary}\n"; 542 | $raw_message .= 'Content-type: Multipart/Alternative; boundary="alt-' . $boundary . '"' . "\n"; 543 | 544 | if ($this->messagetext != null && strlen($this->messagetext) > 0) { 545 | $charset = empty($this->messageTextCharset) ? '' : "; charset=\"{$this->messageTextCharset}\""; 546 | $raw_message .= "\n--alt-{$boundary}\n"; 547 | $raw_message .= 'Content-Type: text/plain' . $charset . "\n\n"; 548 | $raw_message .= $this->messagetext . "\n"; 549 | } 550 | 551 | if ($this->messagehtml != null && strlen($this->messagehtml) > 0) { 552 | $charset = empty($this->messageHtmlCharset) ? '' : "; charset=\"{$this->messageHtmlCharset}\""; 553 | $raw_message .= "\n--alt-{$boundary}\n"; 554 | $raw_message .= 'Content-Type: text/html' . $charset . "\n\n"; 555 | $raw_message .= $this->messagehtml . "\n"; 556 | } 557 | $raw_message .= "\n--alt-{$boundary}--\n"; 558 | 559 | foreach ($this->attachments as $attachment) { 560 | $raw_message .= "\n--{$boundary}\n"; 561 | $raw_message .= 'Content-Type: ' . $attachment['mimeType'] . '; name="' . $attachment['name'] . '"' . "\n"; 562 | $raw_message .= 'Content-Disposition: ' . $attachment['attachmentType'] . "\n"; 563 | if (!empty($attachment['contentId'])) { 564 | $raw_message .= 'Content-ID: ' . $attachment['contentId'] . '' . "\n"; 565 | } 566 | $raw_message .= 'Content-Transfer-Encoding: base64' . "\n"; 567 | $raw_message .= "\n" . chunk_split(base64_encode($attachment['data']), 76, "\n") . "\n"; 568 | } 569 | 570 | $raw_message .= "\n--{$boundary}--\n"; 571 | 572 | if (!$encode) { 573 | return $raw_message; 574 | } 575 | 576 | $this->raw_message = base64_encode($raw_message); 577 | 578 | return $this->raw_message; 579 | } 580 | 581 | /** 582 | * Encode recipient with the specified charset in `recipientsCharset` 583 | * 584 | * @return string Encoded recipients joined with comma 585 | */ 586 | public function encodeRecipients($recipient) { 587 | if (is_array($recipient)) { 588 | return join(', ', array_map(array($this, 'encodeRecipients'), $recipient)); 589 | } 590 | 591 | if (preg_match("/(.*)<(.*)>/", $recipient, $regs)) { 592 | $recipient = '=?' . $this->recipientsCharset . '?B?' . base64_encode($regs[1]) . '?= <' . $regs[2] . '>'; 593 | } 594 | 595 | return $recipient; 596 | } 597 | 598 | /** 599 | * Validates whether the message object has sufficient information to submit a request to SES. 600 | * 601 | * This does not guarantee the message will arrive, nor that the request will succeed; 602 | * instead, it makes sure that no required fields are missing. 603 | * 604 | * This is used internally before attempting a SendEmail or SendRawEmail request, 605 | * but it can be used outside of this file if verification is desired. 606 | * May be useful if e.g. the data is being populated from a form; developers can generally 607 | * use this function to verify completeness instead of writing custom logic. 608 | * 609 | * @return boolean 610 | */ 611 | public function validate() { 612 | // at least one destination is required 613 | if (count($this->to) == 0 && count($this->cc) == 0 && count($this->bcc) == 0) { 614 | return false; 615 | } 616 | 617 | // sender is required 618 | if ($this->from == null || strlen($this->from) == 0) { 619 | return false; 620 | } 621 | 622 | // subject is required 623 | if (($this->subject == null || strlen($this->subject) == 0)) { 624 | return false; 625 | } 626 | 627 | // message is required 628 | if ((empty($this->messagetext) || strlen((string) $this->messagetext) == 0) 629 | && (empty($this->messagehtml) || strlen((string) $this->messagehtml) == 0)) { 630 | return false; 631 | } 632 | 633 | return true; 634 | } 635 | } 636 | -------------------------------------------------------------------------------- /src/SimpleEmailServiceRequest.php: -------------------------------------------------------------------------------- 1 | ses = $ses; 31 | $this->verb = $verb; 32 | $this->response = (object) array('body' => '', 'code' => 0, 'error' => false); 33 | } 34 | 35 | 36 | /** 37 | * Set SES class 38 | * 39 | * @param SimpleEmailService $ses 40 | * @return SimpleEmailServiceRequest $this 41 | */ 42 | public function setSES(SimpleEmailService $ses) { 43 | $this->ses = $ses; 44 | 45 | return $this; 46 | } 47 | 48 | /** 49 | * Set HTTP method 50 | * 51 | * @param string $verb 52 | * @return SimpleEmailServiceRequest $this 53 | */ 54 | public function setVerb($verb) { 55 | $this->verb = $verb; 56 | 57 | return $this; 58 | } 59 | 60 | /** 61 | * Set request parameter 62 | * 63 | * @param string $key Key 64 | * @param string $value Value 65 | * @param boolean $replace Whether to replace the key if it already exists (default true) 66 | * @return SimpleEmailServiceRequest $this 67 | */ 68 | public function setParameter($key, $value, $replace = true) { 69 | if(!$replace && isset($this->parameters[$key])) { 70 | $temp = (array)($this->parameters[$key]); 71 | $temp[] = $value; 72 | $this->parameters[$key] = $temp; 73 | } else { 74 | $this->parameters[$key] = $value; 75 | } 76 | 77 | return $this; 78 | } 79 | 80 | /** 81 | * Get the params for the request 82 | * 83 | * @return array $params 84 | * @deprecated 85 | */ 86 | public function getParametersEncoded() { 87 | $params = array(); 88 | 89 | foreach ($this->parameters as $var => $value) { 90 | if(is_array($value)) { 91 | foreach($value as $v) { 92 | $params[] = $var.'='.$this->__customUrlEncode($v); 93 | } 94 | } else { 95 | $params[] = $var.'='.$this->__customUrlEncode($value); 96 | } 97 | } 98 | 99 | sort($params, SORT_STRING); 100 | 101 | return $params; 102 | } 103 | 104 | /** 105 | * Clear the request parameters 106 | * @return SimpleEmailServiceRequest $this 107 | */ 108 | public function clearParameters() { 109 | $this->parameters = array(); 110 | return $this; 111 | } 112 | 113 | /** 114 | * Instantiate and setup CURL handler for sending requests. 115 | * Instance is cashed in `$this->curl_handler` 116 | * 117 | * @return resource $curl_handler 118 | */ 119 | protected function getCurlHandler() { 120 | if (!empty($this->curl_handler)) 121 | return $this->curl_handler; 122 | 123 | $curl = curl_init(); 124 | curl_setopt($curl, CURLOPT_USERAGENT, 'SimpleEmailService/php'); 125 | 126 | curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, ($this->ses->verifyHost() ? 2 : 0)); 127 | curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, ($this->ses->verifyPeer() ? 1 : 0)); 128 | curl_setopt($curl, CURLOPT_HEADER, false); 129 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, false); 130 | curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback')); 131 | curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); 132 | 133 | foreach(self::$curlOptions as $option => $value) { 134 | curl_setopt($curl, $option, $value); 135 | } 136 | 137 | $this->curl_handler = $curl; 138 | 139 | return $this->curl_handler; 140 | } 141 | 142 | /** 143 | * Get the response 144 | * 145 | * @return object | false 146 | */ 147 | public function getResponse() { 148 | 149 | $url = 'https://'.$this->ses->getHost().'/'; 150 | ksort($this->parameters); 151 | $query = http_build_query($this->parameters, '', '&', PHP_QUERY_RFC1738); 152 | $headers = $this->getHeaders($query); 153 | 154 | $curl_handler = $this->getCurlHandler(); 155 | curl_setopt($curl_handler, CURLOPT_CUSTOMREQUEST, $this->verb); 156 | 157 | // Request types 158 | switch ($this->verb) { 159 | case 'GET': 160 | case 'DELETE': 161 | $url .= '?'.$query; 162 | break; 163 | 164 | case 'POST': 165 | curl_setopt($curl_handler, CURLOPT_POSTFIELDS, $query); 166 | $headers[] = 'Content-Type: application/x-www-form-urlencoded'; 167 | break; 168 | } 169 | curl_setopt($curl_handler, CURLOPT_HTTPHEADER, $headers); 170 | curl_setopt($curl_handler, CURLOPT_URL, $url); 171 | 172 | 173 | // Execute, grab errors 174 | if (curl_exec($curl_handler)) { 175 | $this->response->code = curl_getinfo($curl_handler, CURLINFO_HTTP_CODE); 176 | } else { 177 | $this->response->error = array( 178 | 'curl' => true, 179 | 'code' => curl_errno($curl_handler), 180 | 'message' => curl_error($curl_handler), 181 | ); 182 | } 183 | 184 | // cleanup for reusing the current instance for multiple requests 185 | curl_setopt($curl_handler, CURLOPT_POSTFIELDS, ''); 186 | $this->parameters = array(); 187 | 188 | // Parse body into XML 189 | if ($this->response->error === false && !empty($this->response->body)) { 190 | $this->response->body = simplexml_load_string($this->response->body); 191 | 192 | // Grab SES errors 193 | if (!in_array($this->response->code, array(200, 201, 202, 204)) 194 | && isset($this->response->body->Error)) { 195 | $error = $this->response->body->Error; 196 | $output = array(); 197 | $output['curl'] = false; 198 | $output['Error'] = array(); 199 | $output['Error']['Type'] = (string)$error->Type; 200 | $output['Error']['Code'] = (string)$error->Code; 201 | $output['Error']['Message'] = (string)$error->Message; 202 | $output['RequestId'] = (string)$this->response->body->RequestId; 203 | 204 | $this->response->error = $output; 205 | unset($this->response->body); 206 | } 207 | } 208 | 209 | $response = $this->response; 210 | $this->response = (object) array('body' => '', 'code' => 0, 'error' => false); 211 | 212 | return $response; 213 | } 214 | 215 | /** 216 | * Get request headers 217 | * @param string $query 218 | * @return array 219 | */ 220 | protected function getHeaders($query) { 221 | $headers = array(); 222 | 223 | if ($this->ses->getRequestSignatureVersion() == SimpleEmailService::REQUEST_SIGNATURE_V4) { 224 | $date = (new DateTime('now', new DateTimeZone('UTC')))->format('Ymd\THis\Z'); 225 | $headers[] = 'X-Amz-Date: ' . $date; 226 | $headers[] = 'Host: ' . $this->ses->getHost(); 227 | $headers[] = 'Authorization: ' . $this->__getAuthHeaderV4($date, $query); 228 | 229 | } else { 230 | // must be in format 'Sun, 06 Nov 1994 08:49:37 GMT' 231 | $date = gmdate('D, d M Y H:i:s e'); 232 | $auth = 'AWS3-HTTPS AWSAccessKeyId='.$this->ses->getAccessKey(); 233 | $auth .= ',Algorithm=HmacSHA256,Signature='.$this->__getSignature($date); 234 | 235 | $headers[] = 'Date: ' . $date; 236 | $headers[] = 'Host: ' . $this->ses->getHost(); 237 | $headers[] = 'X-Amzn-Authorization: ' . $auth; 238 | } 239 | 240 | return $headers; 241 | } 242 | 243 | /** 244 | * Destroy any leftover handlers 245 | */ 246 | public function __destruct() { 247 | if (!empty($this->curl_handler)) 248 | @curl_close($this->curl_handler); 249 | } 250 | 251 | /** 252 | * CURL write callback 253 | * 254 | * @param resource $curl CURL resource 255 | * @param string $data Data 256 | * @return integer 257 | */ 258 | private function __responseWriteCallback($curl, $data) { 259 | if (!isset($this->response->body)) { 260 | $this->response->body = $data; 261 | } else { 262 | $this->response->body .= $data; 263 | } 264 | 265 | return strlen($data); 266 | } 267 | 268 | /** 269 | * Contributed by afx114 270 | * URL encode the parameters as per http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?Query_QueryAuth.html 271 | * PHP's rawurlencode() follows RFC 1738, not RFC 3986 as required by Amazon. The only difference is the tilde (~), so convert it back after rawurlencode 272 | * See: http://www.morganney.com/blog/API/AWS-Product-Advertising-API-Requires-a-Signed-Request.php 273 | * 274 | * @param string $var String to encode 275 | * @return string 276 | * @deprecated 277 | */ 278 | private function __customUrlEncode($var) { 279 | return str_replace('%7E', '~', rawurlencode($var)); 280 | } 281 | 282 | /** 283 | * Generate the auth string using Hmac-SHA256 284 | * 285 | * @internal Used by SimpleEmailServiceRequest::getResponse() 286 | * @param string $string String to sign 287 | * @return string 288 | */ 289 | private function __getSignature($string) { 290 | return base64_encode(hash_hmac('sha256', $string, $this->ses->getSecretKey(), true)); 291 | } 292 | 293 | /** 294 | * @param string $key 295 | * @param string $dateStamp 296 | * @param string $regionName 297 | * @param string $serviceName 298 | * @param string $algo 299 | * @return string 300 | */ 301 | private function __getSigningKey($key, $dateStamp, $regionName, $serviceName, $algo) { 302 | $kDate = hash_hmac($algo, $dateStamp, 'AWS4' . $key, true); 303 | $kRegion = hash_hmac($algo, $regionName, $kDate, true); 304 | $kService = hash_hmac($algo, $serviceName, $kRegion, true); 305 | 306 | return hash_hmac($algo,'aws4_request', $kService, true); 307 | } 308 | 309 | /** 310 | * Implementation of AWS Signature Version 4 311 | * @see https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html 312 | * @param string $amz_datetime 313 | * @param string $query 314 | * @return string 315 | */ 316 | private function __getAuthHeaderV4($amz_datetime, $query) { 317 | $amz_date = substr($amz_datetime, 0, 8); 318 | $algo = 'sha256'; 319 | $aws_algo = 'AWS4-HMAC-' . strtoupper($algo); 320 | 321 | $host_parts = explode('.', $this->ses->getHost()); 322 | $service = $host_parts[0]; 323 | $region = $host_parts[1]; 324 | 325 | $canonical_uri = '/'; 326 | if($this->verb === 'POST') { 327 | $canonical_querystring = ''; 328 | $payload_data = $query; 329 | } else { 330 | $canonical_querystring = $query; 331 | $payload_data = ''; 332 | } 333 | 334 | // ************* TASK 1: CREATE A CANONICAL REQUEST ************* 335 | $canonical_headers_list = [ 336 | 'host:' . $this->ses->getHost(), 337 | 'x-amz-date:' . $amz_datetime 338 | ]; 339 | 340 | $canonical_headers = implode("\n", $canonical_headers_list) . "\n"; 341 | $signed_headers = 'host;x-amz-date'; 342 | $payload_hash = hash($algo, $payload_data, false); 343 | 344 | $canonical_request = implode("\n", array( 345 | $this->verb, 346 | $canonical_uri, 347 | $canonical_querystring, 348 | $canonical_headers, 349 | $signed_headers, 350 | $payload_hash 351 | )); 352 | 353 | // ************* TASK 2: CREATE THE STRING TO SIGN************* 354 | $credential_scope = $amz_date. '/' . $region . '/' . $service . '/' . 'aws4_request'; 355 | $string_to_sign = implode("\n", array( 356 | $aws_algo, 357 | $amz_datetime, 358 | $credential_scope, 359 | hash($algo, $canonical_request, false) 360 | )); 361 | 362 | // ************* TASK 3: CALCULATE THE SIGNATURE ************* 363 | // Create the signing key using the function defined above. 364 | $signing_key = $this->__getSigningKey($this->ses->getSecretKey(), $amz_date, $region, $service, $algo); 365 | 366 | // Sign the string_to_sign using the signing_key 367 | $signature = hash_hmac($algo, $string_to_sign, $signing_key, false); 368 | 369 | // ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST ************* 370 | return $aws_algo . ' ' . implode(', ', array( 371 | 'Credential=' . $this->ses->getAccessKey() . '/' . $credential_scope, 372 | 'SignedHeaders=' . $signed_headers , 373 | 'Signature=' . $signature 374 | )); 375 | } 376 | } 377 | -------------------------------------------------------------------------------- /tests/SimpleEmailServiceMessageTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 10 | } 11 | } -------------------------------------------------------------------------------- /tests/SimpleEmailServiceRequestTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 10 | } 11 | } -------------------------------------------------------------------------------- /tests/SimpleEmailServiceTest.php: -------------------------------------------------------------------------------- 1 | prophet = new \Prophecy\Prophet; 12 | // } 13 | 14 | // protected function tearDown() 15 | // { 16 | // $this->prophet->checkPredictions(); 17 | // } 18 | 19 | public function testIfSetMethodsReturnSelf() 20 | { 21 | $ses = new SimpleEmailService(); 22 | 23 | $this->assertSame($ses, $ses->setAuth('', '')); 24 | $this->assertSame($ses, $ses->setVerifyHost(false)); 25 | $this->assertSame($ses, $ses->setVerifyPeer(false)); 26 | $this->assertSame($ses, $ses->setBulkMode(false)); 27 | } 28 | 29 | public function testSetGet() 30 | { 31 | $ses = new SimpleEmailService(); 32 | 33 | foreach([true, false] as $opt) { 34 | $this->assertSame($opt, $ses->enableVerifyHost($opt)->verifyHost()); 35 | $this->assertSame($opt, $ses->enableVerifyPeer($opt)->verifyPeer()); 36 | 37 | $this->assertSame($opt, $ses->setVerifyHost($opt)->getVerifyHost()); 38 | $this->assertSame($opt, $ses->setVerifyPeer($opt)->getVerifyPeer()); 39 | $this->assertSame($opt, $ses->setBulkMode($opt)->getBulkMode()); 40 | } 41 | 42 | foreach(['a', 'b', 'c'] as $opt) { 43 | $ses->setAuth($opt, $opt); 44 | $this->assertSame($opt, $ses->getAccessKey()); 45 | $this->assertSame($opt, $ses->getSecretKey()); 46 | $this->assertSame($opt, $ses->setHost($opt)->getHost()); 47 | } 48 | } 49 | 50 | /** 51 | * @dataProvider initParams 52 | */ 53 | public function testSetAuth($accessKey, $secretKey, $host) 54 | { 55 | $ses = new SimpleEmailService($accessKey, $secretKey, $host); 56 | $this->assertSame($accessKey, $ses->getAccessKey()); 57 | $this->assertSame($secretKey, $ses->getSecretKey()); 58 | $this->assertSame($host, $ses->getHost()); 59 | } 60 | 61 | public function initParams() 62 | { 63 | return [ 64 | ['accessKey', 'secretKey', null], 65 | ['a', 'b', SimpleEmailService::AWS_US_EAST_1], 66 | ]; 67 | } 68 | 69 | /** 70 | * @dataProvider validListVerifiedEmailAddresses 71 | */ 72 | public function testListVerifiedEmailAddresses($response, $expected) 73 | { 74 | $observer = $this->getMockBuilder(SimpleEmailServiceRequest::class) 75 | ->setMethods(['setParameter', 'getResponse']) 76 | ->getMock(); 77 | 78 | $observer->expects($this->once()) 79 | ->method('setParameter') 80 | ->with($this->equalTo('Action'), $this->equalTo('ListVerifiedEmailAddresses')); 81 | 82 | $observer->expects($this->once()) 83 | ->method('getResponse') 84 | ->willReturn($response); 85 | 86 | $ses = new SimpleEmailService(); 87 | $ses->setRequestHandler($observer); 88 | $this->assertSame($expected, $ses->listVerifiedEmailAddresses()); 89 | } 90 | 91 | public function validListVerifiedEmailAddresses() 92 | { 93 | $faker = Faker\Factory::create(); 94 | $emails = array_map(function() use ($faker) { return $faker->email; }, range(1, 10)); 95 | $request_id = $faker->uuid; 96 | 97 | return [ 98 | array_values([ 99 | 'response' => json_decode(json_encode([ 100 | 'code' => 200, 101 | 'error' => false, 102 | 'body' => [ 103 | 'ResponseMetadata' => [ 104 | 'RequestId' => $request_id, 105 | ], 106 | 'ListVerifiedEmailAddressesResult' => [ 107 | 'VerifiedEmailAddresses' => [ 108 | 'member' => $emails 109 | ] 110 | ] 111 | ] 112 | ])), 113 | 'expected' => [ 114 | 'Addresses' => $emails, 115 | 'RequestId' => $request_id, 116 | ] 117 | ]) 118 | ]; 119 | } 120 | } --------------------------------------------------------------------------------