├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── Pigeon │ ├── IlluminateMailer.php │ ├── InvalidMessageTypeException.php │ ├── MessageAbstract.php │ ├── MessageLayout.php │ ├── Pigeon.php │ ├── PigeonInterface.php │ ├── PigeonServiceProvider.php │ └── UnknownMessageTypeException.php ├── config │ └── pigeon.php └── views │ └── emails │ ├── layouts │ └── default.blade.php │ └── templates │ └── default.blade.php └── tests ├── IlluminateMailerTest.php └── MessageLayoutTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | /todo 2 | /.idea 3 | /vendor 4 | composer.lock 5 | composer.phar -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.6 5 | - 7.0 6 | - 7.1 7 | 8 | sudo: false 9 | 10 | install: travis_retry composer install --no-interaction --prefer-source 11 | 12 | script: vendor/bin/phpunit --verbose 13 | 14 | matrix: 15 | allow_failures: 16 | - php: hhvm 17 | fast_finish: true -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | ========= 3 | 4 | 2016-02-04 - 5.2.0 5 | ----------------- 6 | * Compatibility with Laravel 5.2 7 | * Removed mail pretend functionality 8 | * Must pass testing with PHP 7 9 | 10 | 2016-01-06 - 5.1.2 11 | ----------------- 12 | * Fix composer.json so Pigeon 5.1.* doesn't break composer update to Laravel 5.2.* 13 | 14 | 2015-06-09 - 5.1.1 15 | ----------------- 16 | * Remove PHP 5.4 testing 17 | 18 | 2015-06-09 - 5.1.0 19 | ----------------- 20 | * Compatibility with Laravel 5.1 21 | 22 | 2015-06-01 - 5.0.0 23 | ----------------- 24 | * Initial Version 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Pigeon 2 | =============== 3 | 4 | [![Build Status](https://travis-ci.org/larablocks/pigeon.svg)](https://travis-ci.org/larablocks/pigeon) 5 | [![Latest Stable Version](https://poser.pugx.org/larablocks/pigeon/version)](https://packagist.org/packages/larablocks/pigeon) 6 | [![License](https://poser.pugx.org/larablocks/pigeon/license)](https://packagist.org/packages/larablocks/pigeon) 7 | 8 | A more flexible email message builder for Laravel 5 including chained methods, reusable message type configurations, and email layout and template view management. 9 | 10 | > Note: All Larablocks packages will have releases in line with the major Laravel framework version release. 11 | (Ex. Pigeon 5.4.* is tested to work with Laravel 5.4.* while Pigeon 5.1.* is tested to worked with Laravel 5.1.*) 12 | 13 | ## Installation 14 | 15 | Add `larablocks/pigeon` as a requirement to `composer.json`: 16 | 17 | ```javascript 18 | { 19 | "require": { 20 | "larablocks/pigeon": "~5.4" 21 | } 22 | } 23 | ``` 24 | 25 | Update your packages with `composer update` or install with `composer install`. 26 | 27 | ## Laravel Integration 28 | 29 | To wire this up in your Laravel project you need to add the service provider. Open `app.php`, and add a new item to the providers array. 30 | 31 | ```php 32 | Larablocks\Pigeon\PigeonServiceProvider::class, 33 | ``` 34 | 35 | Then you may add a Facade for more convenient usage. In your `app.php` config file add the following line to the `aliases` array. 36 | 37 | ```php 38 | 'Pigeon' => Larablocks\Pigeon\Pigeon::class, 39 | ``` 40 | 41 | Note: The Pigeon facade will load automatically, so you don't have to add it to the `app.php` file but you may still want 42 | to keep record of the alias. 43 | 44 | To publish the default config file `config/pigeon.php` along with the default email view files use the artisan command: 45 | 46 | `php artisan vendor:publish --provider="Larablocks\Pigeon\PigeonServiceProvider"` 47 | 48 | If you wish to not publish the view files and only publish the config then use the artisan command: 49 | 50 | `php artisan vendor:publish --provider="Larablocks\Pigeon\PigeonServiceProvider" --tag="config"` 51 | 52 | ## Usage as a Facade 53 | 54 | ```php 55 | Pigeon:: 56 | ``` 57 | 58 | ### Setting the General Message Properties 59 | 60 | Pigeon will load all properties set in the `default` area of your config before you construct your message. 61 | 62 | ####Set message addresses: 63 | 64 | All these address add methods can be used with any of the address add functions (to, cc, bcc, replyTo, from, sender) 65 | 66 | Add a single address with no name 67 | ```php 68 | Pigeon::to('john.doe@domain.com') 69 | Pigeon::cc('john.doe@domain.com') 70 | Pigeon::bcc('john.doe@domain.com') 71 | Pigeon::replyTo('john.doe@domain.com') 72 | Pigeon::from('john.doe@domain.com') 73 | Pigeon::sender('john.doe@domain.com') 74 | ``` 75 | 76 | Add a single address with name 77 | ```php 78 | Pigeon::to('john.doe@domain.com', 'John Doe') 79 | .... 80 | ``` 81 | 82 | Add array of addresses with no names 83 | ```php 84 | Pigeon::to(['john.doe@domain.com', 'jane.doe@domain.com']) 85 | ... 86 | ``` 87 | 88 | Add array of addresses some with names, some without names 89 | ```php 90 | Pigeon::to(['john.doe@domain.com' => 'John Doe', 'jane.doe@domain.com']) 91 | ... 92 | ``` 93 | 94 | ####Set Subject: 95 | ```php 96 | Pigeon::subject('My Subject') 97 | ``` 98 | 99 | ####File Attachments: 100 | 101 | Attach a single file with no options 102 | ```php 103 | Pigeon::attach('/path/to/file/attachment') 104 | ``` 105 | 106 | Attach a single file with options 107 | ```php 108 | Pigeon::attach('/path/to/file/attachment', ['as' => 'Attachment', 'mime' => 'jpg']) 109 | ``` 110 | 111 | Attach an array of files 112 | ```php 113 | Pigeon::attach([ 114 | [ 115 | 'path' => '/path/to/file/attachment1' 116 | 'options' => [] 117 | ], 118 | [ 119 | 'path' => '/path/to/file/attachment2' 120 | 'options' => ['as' => 'Attachment 2', 'mime' => 'pdf'] 121 | ] 122 | ]) 123 | ``` 124 | 125 | ### Setting the Message View Properties 126 | 127 | ####Set layout view file: 128 | ```php 129 | Pigeon::layout('emails.layouts.my_layout_view') 130 | ``` 131 | 132 | ####Set template view file: 133 | ```php 134 | Pigeon::template('emails.templates.my_template_view') 135 | ``` 136 | 137 | ####Passing View Variables: 138 | 139 | 140 | Passing simple variables: 141 | ```php 142 | Pigeon::pass([ 143 | 'stringVariable' => 'test string', 144 | 'intVariable' => 2, 145 | 'boolVariable' => true 146 | ]) 147 | ``` 148 | 149 | Passing object variables: 150 | ```php 151 | $user = new User(); 152 | $user->first_name = 'John'; 153 | $user->last_name = 'Doe'; 154 | Pigeon::pass([ 155 | 'userObjectVariable' => $user 156 | ]) 157 | ``` 158 | 159 | If ```pass()``` is used more than once it will merge previously passed variables with the current passed set. 160 | 161 | >Note: Make sure all variables pre-defined in your layout and template view files are passed to your Pigeon message. 162 | 163 | ####Clearing View Variables: 164 | 165 | Clear all previously passed view variables 166 | 167 | ```php 168 | Pigeon::clear() 169 | ``` 170 | 171 | ### Custom Messages Types 172 | 173 | Custom message types will be configured in the `config/pigeon.php` file. In this file you can find examples on how 174 | to properly set up a custom message type. 175 | 176 | #### Default: 177 | 178 | Set your defaults for all messages sent with Pigeon in ```config\pigeon.php``` 179 | 180 | ```php 181 | 'default' => [ 182 | 'to' => [], 183 | 'cc' => [], 184 | 'bcc' => [], 185 | 'replyTo' => [], 186 | 'from' => [], // if nothing is entered here, your mail.php default will still be used 187 | 'sender' => [], 188 | 'attachments' => [], 189 | 'subject' => 'Pigeon Delivery', 190 | 'layout' => 'emails.layouts.default', 191 | 'template' => 'emails.templates.default', 192 | 'message_variables' => [] 193 | ] 194 | ``` 195 | 196 | ####Load Custom Message: 197 | 198 | Set your defaults for a particular message type to be sent with Pigeon in ```config\pigeon.php``` 199 | 200 | ```php 201 | 'custom_message_type' => [ 202 | 'from' => ['from@myapp.com' => 'My Custom App'], 203 | 'subject' => 'My Pigeon Custom Message', 204 | 'layout' => 'emails.layouts.default', 205 | 'template' => 'emails.templates.default' 206 | ] 207 | ``` 208 | 209 | This will load all the message properties from your config defined for `custom_message_type`. 210 | 211 | ```php 212 | Pigeon::type('custom_message_type'); 213 | ``` 214 | 215 | #### Order of Loading: 216 | 217 | Default -> Custom Message (if set and loaded) -> Properties set with individual Pigeon functions 218 | 219 | 220 | ### Sending the Message 221 | 222 | ####Send Message: 223 | ```php 224 | Pigeon::send(); 225 | ``` 226 | 227 | ####Send Raw Message: 228 | 229 | Pass a string as a param for the send() function and it will use the string as a raw message send and will ignore any 230 | view files or view variables assigned. 231 | 232 | ```php 233 | Pigeon::send('This is my raw message'); 234 | ``` 235 | 236 | ### Example - Using it all together 237 | 238 | ```php 239 | Pigeon::to(['john.doe@domain.com', 'jane.doe@domain.com']) 240 | ->cc('fred.doe@domain.com') 241 | ->bcc('george.doe@domain.com') 242 | ->subject('This is the Subject') 243 | ->attach('/path/to/file/attachment') 244 | ->layout('emails.layouts.my_layout_view') 245 | ->template('emails.templates.my_template_view') 246 | ->pass(['firstVariable' => 'test string', 'secondVariable' => 2, 'thirdVariable' => true]) 247 | ->send(); 248 | ``` 249 | 250 | ### Example - Simple call 251 | 252 | ```php 253 | Pigeon::to('me@domain.com')->subject('Testing Pigeon')->send('Sending myself a quick raw message'); 254 | ``` 255 | 256 | ### Example - Sending a custom message 257 | 258 | ```php 259 | Pigeon::type('custom_message_type')->to('me@domain.com')->send(); 260 | ``` 261 | 262 | ## Usage as a Passed Dependency 263 | 264 | To pass Pigeon as a dependency will will pass the interface `Larablocks\Pigeon\PigeonInterface`. For now the only library 265 | that implements this interface is `Larablocks\Pigeon\IlluminateMailer` provided by Laravel but we want to allow for other mailing libraries to be used in the future. 266 | The `config/pigeon.php` config file for Pigeon automatically sets IlluminateMailer as the default mailer library for you. 267 | 268 | ```php 269 | 'library' => 'IlluminateMailer', 270 | ``` 271 | 272 | ###Passing Pigeon to a constructor: 273 | ```php 274 | public function __construct(Larablocks\Pigeon\PigeonInterface $pigeon) 275 | { 276 | $this->pigeon = $pigeon; 277 | } 278 | ``` 279 | 280 | ###Starting a new default message: 281 | 282 | ```php 283 | $this->pigeon->to('me@domain.com')->subject('Pigeon Raw Test Message')->send('Sending myself a quick raw message'); 284 | ``` 285 | 286 | ###Starting a new custom message type: 287 | ```php 288 | $this->pigeon->type('custom_message_type')->to('me@domain.com')->send(); 289 | ``` 290 | 291 | ## License 292 | 293 | Pigeon is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT) -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "larablocks/pigeon", 3 | "type": "library", 4 | "description": "A more flexible email message builder for Laravel 5 including chained methods, reusable message configurations, and message layout and template view management.", 5 | "keywords": [ 6 | "mailer","laravel","laravel 5","mail","email","message","template","views","builder","pigeon" 7 | ], 8 | "license": "MIT", 9 | "authors": [ 10 | { 11 | "name": "Eric Mitkowski", 12 | "email": "eric@soaringtech.com", 13 | "role": "Developer" 14 | } 15 | ], 16 | "require": { 17 | "php": ">=5.6.4", 18 | "illuminate/config": "~5.4", 19 | "illuminate/mail": "~5.4", 20 | "illuminate/log": "~5.4" 21 | }, 22 | "require-dev": { 23 | "fzaninotto/faker": "~1.5", 24 | "mockery/mockery": "0.9.*", 25 | "phpunit/phpunit": "~5.7" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "Larablocks\\Pigeon\\": "src/Pigeon" 30 | } 31 | }, 32 | "autoload-dev": { 33 | "psr-4": { 34 | "Larablocks\\Pigeon\\PHPUnit\\": "tests" 35 | } 36 | }, 37 | "extra": { 38 | "branch-alias": { 39 | "dev-master": "5.4.x-dev" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests/ 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Pigeon/IlluminateMailer.php: -------------------------------------------------------------------------------- 1 | mailer = $mailer; 44 | $this->logger = $logger; 45 | 46 | parent::__construct($message_layout, $config); 47 | } 48 | 49 | /** 50 | * Send Mail 51 | * 52 | * @param null $raw_message 53 | * @return bool 54 | */ 55 | public function send($raw_message = null) 56 | { 57 | // Set Optional Message Data 58 | if (!is_null($raw_message)) { 59 | $send_result = $this->sendRawMessage($raw_message); 60 | } else { 61 | $send_result = $this->sendMessage(); 62 | } 63 | 64 | // Reset to default after send 65 | $this->restoreDefaultMessageType(); 66 | 67 | return (bool) $send_result; 68 | } 69 | 70 | 71 | /** 72 | * Send Message with View 73 | * 74 | * @return bool 75 | */ 76 | private function sendMessage() 77 | { 78 | try { 79 | $this->mailer->send($this->message_layout->getViewLayout(), $this->message_layout->getMessageVariables(), function ($message) { 80 | 81 | if (config('pigeon.dev.override')) { 82 | $message->to(config('pigeon.dev.override_email')); 83 | } else { 84 | $message->to($this->to); 85 | } 86 | 87 | // Set message parts 88 | $message->subject($this->subject) 89 | ->cc($this->cc) 90 | ->bcc($this->bcc) 91 | ->replyTo($this->reply_to) 92 | ->sender($this->sender); 93 | 94 | if (!empty($this->from)) { 95 | $message->from($this->from); 96 | } 97 | 98 | // Set all attachments 99 | foreach ($this->attachments as $a) { 100 | $message->attach($a['path'], $a['options']); 101 | } 102 | }); 103 | 104 | } catch (ErrorException $e) { 105 | $msg = 'Pigeon could not send message: ' . $e->getMessage(); 106 | $this->logger->error($msg); 107 | return false; 108 | } catch (\Swift_TransportException $e) { 109 | $msg = 'SMTP failure: ' . $e->getMessage(); 110 | $this->logger->error($msg); 111 | return false; 112 | } 113 | 114 | return true; 115 | } 116 | 117 | 118 | /** 119 | * Send Raw Message 120 | * 121 | * @param $message 122 | * @return bool 123 | */ 124 | private function sendRawMessage($message) 125 | { 126 | try { 127 | $this->mailer->raw($message, function ($message) { 128 | 129 | 130 | if (config('pigeon.dev.override')) { 131 | $message->to(config('pigeon.dev.override_email')); 132 | } else { 133 | $message->to($this->to); 134 | } 135 | 136 | // Set message parts 137 | $message->subject($this->subject) 138 | ->cc($this->cc) 139 | ->bcc($this->bcc) 140 | ->replyTo($this->reply_to) 141 | ->sender($this->sender); 142 | 143 | if (!empty($this->from)) { 144 | $message->from($this->from); 145 | } 146 | 147 | // Set all attachments 148 | foreach ($this->attachments as $a) { 149 | $message->attach($a['path'], $a['options']); 150 | } 151 | }); 152 | } catch (ErrorException $e) { 153 | $msg = 'Pigeon could not send message: ' . $e->getMessage(); 154 | $this->logger->error($msg); 155 | return false; 156 | } catch (\Swift_TransportException $e) { 157 | $msg = 'SMTP failure: ' . $e->getMessage(); 158 | $this->logger->error($msg); 159 | return false; 160 | } 161 | 162 | return true; 163 | } 164 | } -------------------------------------------------------------------------------- /src/Pigeon/InvalidMessageTypeException.php: -------------------------------------------------------------------------------- 1 | message_layout = $message_layout; 117 | $this->config = $config; 118 | 119 | $this->loadConfigType('default'); 120 | } 121 | 122 | /** 123 | * Load Message Type 124 | * 125 | * @param $message_type (set in config file) 126 | * @return $this 127 | */ 128 | public function type($message_type) 129 | { 130 | $this->loadConfigType($message_type); 131 | 132 | return $this; 133 | } 134 | 135 | /** 136 | * Get Current Message Type 137 | * 138 | * @return string 139 | */ 140 | public function getType() 141 | { 142 | return $this->message_type; 143 | } 144 | 145 | /** 146 | * Set From 147 | * 148 | * @param $address 149 | * @param null $name 150 | * @return $this 151 | */ 152 | public function from($address, $name = null) 153 | { 154 | if (is_array($address)) { 155 | $this->addAddressArray($address, 'from'); 156 | } else { 157 | $this->from[$address] = $name; 158 | } 159 | 160 | return $this; 161 | } 162 | 163 | /** 164 | * Set Sender 165 | * 166 | * @param $address 167 | * @param null $name 168 | * @return $this 169 | */ 170 | public function sender($address, $name = null) 171 | { 172 | if (is_array($address)) { 173 | $this->addAddressArray($address, 'sender'); 174 | } else { 175 | $this->sender[$address] = $name; 176 | } 177 | 178 | return $this; 179 | } 180 | 181 | 182 | /** 183 | * Set To 184 | * 185 | * @param $address 186 | * @param null $name 187 | * @return $this 188 | */ 189 | public function to($address, $name = null) 190 | { 191 | if (is_array($address)) { 192 | $this->addAddressArray($address, 'to'); 193 | } else { 194 | $this->to[$address] = $name; 195 | } 196 | 197 | return $this; 198 | } 199 | 200 | /** 201 | * Adds a Carbon Copy(CC) address 202 | * 203 | * @param $address 204 | * @param null $name 205 | * @return $this|object 206 | */ 207 | public function cc($address, $name = null) 208 | { 209 | if (is_array($address)) { 210 | $this->addAddressArray($address, 'cc'); 211 | } else { 212 | $this->cc[$address] = $name; 213 | } 214 | 215 | return $this; 216 | } 217 | 218 | /** 219 | * Adds a Blind Carbon Copy(BCC) address 220 | * 221 | * @param $address 222 | * @param null $name 223 | * @return $this|object 224 | */ 225 | public function bcc($address, $name = null) 226 | { 227 | if (is_array($address)) { 228 | $this->addAddressArray($address, 'bcc'); 229 | } else { 230 | $this->bcc[$address] = $name; 231 | } 232 | 233 | return $this; 234 | } 235 | 236 | /** 237 | * Adds a Reply To address 238 | * 239 | * @param $address 240 | * @param null $name 241 | * @return $this|object 242 | */ 243 | public function replyTo($address, $name = null) 244 | { 245 | if (is_array($address)) { 246 | $this->addAddressArray($address, 'replyTo'); 247 | } else { 248 | $this->reply_to[$address] = $name; 249 | } 250 | 251 | return $this; 252 | } 253 | 254 | /** 255 | * Set Subject 256 | * 257 | * @param $subject 258 | * @return $this|object 259 | */ 260 | public function subject($subject) 261 | { 262 | $this->subject = $subject; 263 | 264 | return $this; 265 | } 266 | 267 | /** 268 | * Set Email Layout 269 | * 270 | * @param $layout_path 271 | * @return $this|object 272 | */ 273 | public function layout($layout_path) 274 | { 275 | $this->message_layout->setViewLayout($layout_path); 276 | 277 | return $this; 278 | } 279 | 280 | /** 281 | * Set Email Template 282 | * 283 | * @param $template_path 284 | * @return $this|object 285 | */ 286 | public function template($template_path) 287 | { 288 | $this->message_layout->setViewTemplate($template_path); 289 | 290 | return $this; 291 | } 292 | 293 | /** 294 | * Pass Message variables 295 | * 296 | * @param array $message_variables 297 | * @return $this 298 | */ 299 | public function pass(array $message_variables) 300 | { 301 | $this->message_layout->includeVariables($message_variables); 302 | 303 | return $this; 304 | } 305 | 306 | 307 | /** 308 | * Clear All Message Variables Assigned (except template) 309 | * 310 | * @return $this 311 | */ 312 | public function clear() 313 | { 314 | $this->message_layout->clearVariables(); 315 | 316 | return $this; 317 | } 318 | 319 | /** 320 | * Attaches file to mail 321 | * 322 | * @param $pathToFile 323 | * @param array $options 324 | * @return $this|object 325 | */ 326 | public function attach($pathToFile, array $options = []) 327 | { 328 | if (is_array($pathToFile)) { 329 | foreach($pathToFile as $attachment) { 330 | 331 | if (isset($attachment['options']) && array_key_exists("options", $attachment)) { 332 | $options = $attachment['options']; 333 | } else { 334 | $options = []; 335 | } 336 | $this->addAttachment($attachment['path'], $options); 337 | } 338 | } else { 339 | $this->addAttachment($pathToFile, $options); 340 | } 341 | 342 | return $this; 343 | } 344 | 345 | /** 346 | * Add Attachment 347 | * 348 | * @param $pathToFile 349 | * @param array $options 350 | */ 351 | private function addAttachment($pathToFile, array $options = []) 352 | { 353 | $attachment['path'] = $pathToFile; 354 | $attachment['options'] = $options; 355 | 356 | array_push($this->attachments, $attachment); 357 | } 358 | 359 | /** 360 | * Adds array of addresses to type 361 | * 362 | * @param array $address_array 363 | * @param $type 364 | * @return bool 365 | */ 366 | private function addAddressArray(array $address_array, $type) 367 | { 368 | foreach ($address_array as $address => $name) { 369 | 370 | if (!method_exists($this, $type)) { 371 | return false; 372 | } 373 | 374 | if (is_int($address)) { 375 | $this->$type($name); 376 | } else { 377 | $this->$type($address, $name); 378 | } 379 | } 380 | 381 | return true; 382 | } 383 | 384 | 385 | /** 386 | * Load the config type passed from configuration file 387 | * 388 | * @param $config_type 389 | * @return bool 390 | * @throws InvalidMessageTypeException 391 | * @throws UnknownMessageTypeException 392 | */ 393 | private function loadConfigType($config_type) 394 | { 395 | // Get Path for config 396 | if ($config_type === 'default') { 397 | $config_path = self::DEFAULT_CONFIG_PATH; 398 | } else { 399 | $config_path = self::DEFAULT_CONFIG_MESSAGE_TYPE_PATH.'.'.$config_type; 400 | } 401 | 402 | $config_array = $this->config->get($config_path); 403 | 404 | if (is_null($config_array)) { 405 | throw new UnknownMessageTypeException('Pigeon config not found for type: '.$config_type); 406 | } 407 | 408 | if (!is_array($config_array)) { 409 | throw new InvalidMessageTypeException('Pigeon config not set up properly for type: '.$config_type); 410 | } 411 | 412 | if($this->setConfigOptions($config_array)) { 413 | $this->message_type = $config_type; 414 | } 415 | 416 | return true; 417 | 418 | } 419 | 420 | /** 421 | * Set Configuration Options 422 | * 423 | * @param array $config_array 424 | * @return bool 425 | */ 426 | private function setConfigOptions(array $config_array) 427 | { 428 | foreach ($config_array as $type => $value) { 429 | $this->setConfigOption($type, $value); 430 | } 431 | 432 | return true; 433 | } 434 | 435 | /** 436 | * Set Specific Config Option 437 | * 438 | * @param $option_type 439 | * @param $option_value 440 | * @return bool 441 | */ 442 | private function setConfigOption($option_type, $option_value) 443 | { 444 | if ($option_type === 'message_variables') { 445 | $option_type = 'pass'; 446 | } else if ($option_type === 'attachments') { 447 | $option_type = 'attach'; 448 | } 449 | 450 | if (!method_exists($this, $option_type)) { 451 | return false; 452 | } 453 | 454 | $this->$option_type($option_value); 455 | 456 | return true; 457 | } 458 | 459 | /** 460 | * Restore Message to Default Configs 461 | * 462 | * @throws InvalidMessageTypeException 463 | * @throws UnknownMessageTypeException 464 | */ 465 | protected function restoreDefaultMessageType() 466 | { 467 | $this->resetMessage(); 468 | $this->loadConfigType('default'); 469 | } 470 | 471 | /** 472 | * Reset Message Properties to empty 473 | */ 474 | private function resetMessage() 475 | { 476 | $this->subject = ''; 477 | $this->from = []; 478 | $this->sender = []; 479 | $this->to = []; 480 | $this->cc = []; 481 | $this->bcc = []; 482 | $this->reply_to = []; 483 | $this->attachments = []; 484 | $this->message_layout->setViewLayout(''); 485 | $this->message_layout->setViewTemplate(''); 486 | $this->message_layout->clearVariables(); 487 | } 488 | } -------------------------------------------------------------------------------- /src/Pigeon/MessageLayout.php: -------------------------------------------------------------------------------- 1 | assignTemplate(); 49 | } 50 | 51 | 52 | /** 53 | * Set Email View Layout 54 | * 55 | * @param $view 56 | */ 57 | public function setViewLayout($view) 58 | { 59 | $this->view_layout = $view; 60 | } 61 | 62 | /** 63 | * Get Email View Layout 64 | * 65 | * @return mixed 66 | */ 67 | public function getViewLayout() 68 | { 69 | return $this->view_layout; 70 | } 71 | 72 | /** 73 | * Set Email View Template 74 | * 75 | * @param $template 76 | */ 77 | public function setViewTemplate($template) 78 | { 79 | $this->view_template = $template; 80 | 81 | $this->assignTemplate(); 82 | } 83 | 84 | 85 | /** 86 | * Get Email View Template 87 | * 88 | * @return mixed 89 | */ 90 | public function getViewTemplate() 91 | { 92 | return $this->view_template; 93 | } 94 | 95 | /** 96 | * Assign Message Variables 97 | * 98 | * @param array $message_variables 99 | */ 100 | public function includeVariables(array $message_variables) 101 | { 102 | // Remove the default template variable key from any variable assignments 103 | unset($message_variables[self::TEMPLATE_VARIABLE]); 104 | 105 | $this->message_variables = array_merge($this->message_variables, $message_variables); 106 | $this->assignTemplate(); 107 | } 108 | 109 | 110 | /** 111 | * Clear existing message variables 112 | * 113 | */ 114 | public function clearVariables() 115 | { 116 | $this->message_variables = []; 117 | $this->assignTemplate(); 118 | } 119 | 120 | /** 121 | * Get Message Variables 122 | * 123 | * @return mixed 124 | */ 125 | public function getMessageVariables() 126 | { 127 | return $this->message_variables; 128 | } 129 | 130 | /** 131 | * Assign the template variable into body data 132 | * 133 | */ 134 | private function assignTemplate() 135 | { 136 | $this->message_variables['_template'] = $this->view_template; 137 | } 138 | 139 | } -------------------------------------------------------------------------------- /src/Pigeon/Pigeon.php: -------------------------------------------------------------------------------- 1 | app->bind('Larablocks\Pigeon\PigeonInterface', 'Larablocks\Pigeon\\'.config('pigeon.library')); 23 | 24 | // Bind the Pigeon Interface to the facade 25 | $this->app->bind('pigeon', 'Larablocks\Pigeon\PigeonInterface'); 26 | 27 | // Load Pigeon alias for the user if not set in app.php 28 | $aliases = config('app.aliases'); 29 | if (empty($aliases['Pigeon'])) { 30 | AliasLoader::getInstance()->alias('Pigeon', 'Larablocks\Pigeon\Pigeon'); 31 | } 32 | } 33 | 34 | public function boot() 35 | { 36 | $this->publishes([ 37 | __DIR__.'/../config/pigeon.php' => config_path('pigeon.php'), 38 | ], 'config'); 39 | 40 | $this->publishes([ 41 | __DIR__.'/../views/' => base_path('resources/views'), 42 | ], 'views'); 43 | 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /src/Pigeon/UnknownMessageTypeException.php: -------------------------------------------------------------------------------- 1 | 'IlluminateMailer', 12 | 13 | /* 14 | * If you want to have all emails sent through pigeon hijacked and sent to a test email of your choice then 15 | * set the .env variables below 16 | * 17 | */ 18 | 'dev' => [ 19 | 'override' => env('PIGEON_DEV_OVERRIDE', false), 20 | 'override_email' => env('PIGEON_DEV_OVERRIDE_EMAIL', 'dev@mydomain.com') 21 | ], 22 | 23 | /* 24 | * Choose Default Message Configs that will load for any Pigeon instance. 25 | * These will be overridden by using a message type or changing variables with 26 | * Pigeon functions. 27 | * 28 | * 29 | */ 30 | 'default' => [ 31 | 'to' => [], 32 | 'cc' => [], 33 | 'bcc' => [], 34 | 'replyTo' => [], 35 | 'from' => [], // if nothing is entered here, your mail.php default will still be used 36 | 'sender' => [], 37 | 'attachments' => [], 38 | 'subject' => 'Pigeon Delivery', 39 | 'layout' => 'emails.layouts.default', 40 | 'template' => 'emails.templates.default', 41 | 'message_variables' => [] 42 | ], 43 | 44 | /* 45 | * Set default configs for specific message types. 46 | * 47 | * ---Option types--- 48 | * to - single or array of email address 49 | * cc - single or array of email address 50 | * bcc - single or array of email address 51 | * replyTo - single or array of email address 52 | * from - single or array of email address 53 | * sender - single or array of email address 54 | * subject - string 55 | * attachments - array of attachments 56 | * layout - view file path 57 | * template - view file path 58 | * message_variables - array of message variables 59 | 60 | * 61 | * Ex. 62 | * 'user_welcome' => [ 63 | * 64 | * 'cc' => ['john.doe@myapp.com', 'jane.doe@myapp.com'], 65 | * 'bcc' => ['customerservice@myapp.com' => 'Customer Service'], 66 | * 'replyTo' => 'contact@myapp.com', 67 | * 'from' => ['from@myapp.com' => 'My App'], 68 | * 'sender' => 'sender@mysmtp.com', 69 | * 'subject' => 'Welcome New Customer', 70 | * 'attachments' => [ 71 | * 'path' => base_path().'/public/files/test.pdf', 72 | * 'options' => [ 73 | * 'as' => 'My Test PDF' 74 | * ] 75 | * ], 76 | * 'layout' => 'emails.layouts.customer', 77 | * 'template' => 'emails.templates.customer.welcome', 78 | * 'message_variables' = ['appName' => 'My App', 'appUrl' => 'www.myapp.com'], 79 | * 80 | * ] 81 | * 82 | */ 83 | 'message_types' => [ 84 | /* Message Type Test - can remove after testing */ 85 | 'custom_message_type' => [ 86 | 'from' => ['from@myapp.com' => 'My Custom App'], 87 | 'subject' => 'My Pigeon Custom Message', 88 | 'layout' => 'emails.layouts.default', 89 | 'template' => 'emails.templates.default' 90 | ] 91 | ] 92 | ]; 93 | 94 | -------------------------------------------------------------------------------- /src/views/emails/layouts/default.blade.php: -------------------------------------------------------------------------------- 1 | @include($_template) 2 | -------------------------------------------------------------------------------- /src/views/emails/templates/default.blade.php: -------------------------------------------------------------------------------- 1 | Default Message Template -------------------------------------------------------------------------------- /tests/IlluminateMailerTest.php: -------------------------------------------------------------------------------- 1 | getMailerMock(); 18 | $mailer->shouldReceive('send')->once()->andReturn(true); 19 | 20 | $layout = $this->getLayoutMock(); 21 | $layout->shouldReceive('getViewLayout')->once()->andReturn('emails.layouts.default'); 22 | $layout->shouldReceive('getMessageVariables')->once()->andReturn([]); 23 | $layout->shouldReceive('clearVariables')->once(); 24 | 25 | $mailer = new IlluminateMailer($mailer, $layout, $this->getConfigMock(), $this->getLoggerMock()); 26 | 27 | $this->assertTrue($mailer->send()); 28 | } 29 | 30 | public function testRawMessageCanBeSent() 31 | { 32 | $mailer = $this->getMailerMock(); 33 | $mailer->shouldReceive('raw')->once()->andReturn(true); 34 | 35 | $layout = $this->getLayoutMock(); 36 | $layout->shouldReceive('clearVariables')->once(); 37 | 38 | $mailer = new IlluminateMailer($mailer, $layout, $this->getConfigMock(), $this->getLoggerMock()); 39 | 40 | $this->assertTrue($mailer->send('Raw Message')); 41 | } 42 | 43 | public function testTypeDefaultSet() 44 | { 45 | $mailer = new IlluminateMailer($this->getMailerMock(), $this->getLayoutMock(), $this->getConfigMock(), $this->getLoggerMock()); 46 | 47 | $this->assertEquals($mailer, $mailer->type('default')); 48 | $this->assertEquals('default', $mailer->getType()); 49 | 50 | } 51 | 52 | public function testCustomTypeSet() 53 | { 54 | $config = m::mock('Illuminate\Config\Repository'); 55 | $config->shouldReceive('get')->once()->andReturn([ 56 | 'to' => [], 57 | 'cc' => [], 58 | 'bcc' => [], 59 | 'replyTo' => [], 60 | 'from' => [], 61 | 'sender' => [], 62 | 'attachments' => [], 63 | 'subject' => 'Pigeon Delivery', 64 | 'layout' => 'emails.layouts.default', 65 | 'template' => 'emails.templates.default', 66 | 'message_variables' => [] 67 | ]); 68 | 69 | $config->shouldReceive('get')->once()->andReturn([ 70 | 'to' => [], 71 | 'cc' => [], 72 | 'bcc' => [], 73 | 'replyTo' => [], 74 | 'from' => [], 75 | 'sender' => [], 76 | 'attachments' => [], 77 | 'subject' => 'Custom Subject', 78 | 'layout' => 'emails.layouts.custom', 79 | 'template' => 'emails.templates.custom', 80 | 'message_variables' => ['custom' => 'Test Custom'] 81 | ]); 82 | 83 | 84 | $config->shouldReceive('get')->once()->andReturn([ 85 | 'bad_variables' => 'test' 86 | ]); 87 | 88 | $mailer = new IlluminateMailer($this->getMailerMock(), $this->getLayoutMock(), $config, $this->getLoggerMock()); 89 | 90 | // Test Correct Custom Configs 91 | $this->assertEquals($mailer, $mailer->type('custom')); 92 | $this->assertEquals('custom', $mailer->getType()); 93 | $this->assertAttributeEquals('Custom Subject', 'subject', $mailer); 94 | 95 | // Test Custom Config with bad option 96 | $this->assertEquals($mailer, $mailer->type('bad_custom')); 97 | } 98 | 99 | public function testSwiftMailerPropertySetting() 100 | { 101 | $mailer = new IlluminateMailer($this->getMailerMock(), $this->getLayoutMock(), $this->getConfigMock(), $this->getLoggerMock()); 102 | 103 | // Test to 104 | $mailer->to('john.doe@domain.com'); 105 | $this->assertAttributeEquals(['john.doe@domain.com' => null], 'to', $mailer); 106 | 107 | $mailer->to('jim.doe@domain.com', 'Jim Doe'); 108 | $this->assertAttributeEquals(['john.doe@domain.com' => null, 'jim.doe@domain.com' => 'Jim Doe'], 'to', $mailer); 109 | 110 | $mailer->to(['jane.doe@domain.com' => 'Jane Doe', 'fred.doe@gmail.com']); 111 | $this->assertAttributeEquals(['john.doe@domain.com' => null, 'jim.doe@domain.com' => 'Jim Doe', 'jane.doe@domain.com' => 'Jane Doe', 'fred.doe@gmail.com' => null], 'to', $mailer); 112 | 113 | // Test cc 114 | $mailer->cc('john.doe@domain.com'); 115 | $this->assertAttributeEquals(['john.doe@domain.com' => null], 'cc', $mailer); 116 | 117 | $mailer->cc('jim.doe@domain.com', 'Jim Doe'); 118 | $this->assertAttributeEquals(['john.doe@domain.com' => null, 'jim.doe@domain.com' => 'Jim Doe'], 'cc', $mailer); 119 | 120 | $mailer->cc(['jane.doe@domain.com' => 'Jane Doe', 'fred.doe@gmail.com']); 121 | $this->assertAttributeEquals(['john.doe@domain.com' => null, 'jim.doe@domain.com' => 'Jim Doe', 'jane.doe@domain.com' => 'Jane Doe', 'fred.doe@gmail.com' => null], 'cc', $mailer); 122 | 123 | // Test bcc 124 | $mailer->bcc('john.doe@domain.com'); 125 | $this->assertAttributeEquals(['john.doe@domain.com' => null], 'bcc', $mailer); 126 | 127 | $mailer->bcc('jim.doe@domain.com', 'Jim Doe'); 128 | $this->assertAttributeEquals(['john.doe@domain.com' => null, 'jim.doe@domain.com' => 'Jim Doe'], 'bcc', $mailer); 129 | 130 | $mailer->bcc(['jane.doe@domain.com' => 'Jane Doe', 'fred.doe@gmail.com']); 131 | $this->assertAttributeEquals(['john.doe@domain.com' => null, 'jim.doe@domain.com' => 'Jim Doe', 'jane.doe@domain.com' => 'Jane Doe', 'fred.doe@gmail.com' => null], 'bcc', $mailer); 132 | 133 | // Test replyTo 134 | $mailer->replyTo('john.doe@domain.com'); 135 | $this->assertAttributeEquals(['john.doe@domain.com' => null], 'reply_to', $mailer); 136 | 137 | $mailer->replyTo('jim.doe@domain.com', 'Jim Doe'); 138 | $this->assertAttributeEquals(['john.doe@domain.com' => null, 'jim.doe@domain.com' => 'Jim Doe'], 'reply_to', $mailer); 139 | 140 | $mailer->replyTo(['jane.doe@domain.com' => 'Jane Doe', 'fred.doe@gmail.com']); 141 | $this->assertAttributeEquals(['john.doe@domain.com' => null, 'jim.doe@domain.com' => 'Jim Doe', 'jane.doe@domain.com' => 'Jane Doe', 'fred.doe@gmail.com' => null], 'reply_to', $mailer); 142 | 143 | // Test from 144 | $mailer->from('john.doe@domain.com'); 145 | $this->assertAttributeEquals(['john.doe@domain.com' => null], 'from', $mailer); 146 | 147 | $mailer->from('jim.doe@domain.com', 'Jim Doe'); 148 | $this->assertAttributeEquals(['john.doe@domain.com' => null, 'jim.doe@domain.com' => 'Jim Doe'], 'from', $mailer); 149 | 150 | $mailer->from(['jane.doe@domain.com' => 'Jane Doe', 'fred.doe@gmail.com']); 151 | $this->assertAttributeEquals(['john.doe@domain.com' => null, 'jim.doe@domain.com' => 'Jim Doe', 'jane.doe@domain.com' => 'Jane Doe', 'fred.doe@gmail.com' => null], 'from', $mailer); 152 | 153 | // Test sender 154 | $mailer->sender('john.doe@domain.com'); 155 | $this->assertAttributeEquals(['john.doe@domain.com' => null], 'sender', $mailer); 156 | 157 | $mailer->sender('jim.doe@domain.com', 'Jim Doe'); 158 | $this->assertAttributeEquals(['john.doe@domain.com' => null, 'jim.doe@domain.com' => 'Jim Doe'], 'sender', $mailer); 159 | 160 | $mailer->sender(['jane.doe@domain.com' => 'Jane Doe', 'fred.doe@gmail.com']); 161 | $this->assertAttributeEquals(['john.doe@domain.com' => null, 'jim.doe@domain.com' => 'Jim Doe', 'jane.doe@domain.com' => 'Jane Doe', 'fred.doe@gmail.com' => null], 'sender', $mailer); 162 | 163 | // Test subject 164 | $mailer->subject('Test Subject'); 165 | $this->assertAttributeEquals('Test Subject', 'subject', $mailer); 166 | 167 | // Test attach 168 | $mailer->attach('/public/pdf/test1.pdf'); 169 | $this->assertAttributeEquals([0 => ['path' => '/public/pdf/test1.pdf', 'options' => []]], 'attachments', $mailer); 170 | 171 | $mailer->attach('/public/pdf/test2.pdf', ['as' => 'My Test PDF', 'mime' => 'pdf']); 172 | $this->assertAttributeEquals( 173 | [ 174 | 0 => ['path' => '/public/pdf/test1.pdf', 'options' => []], 175 | 1 => ['path' => '/public/pdf/test2.pdf', 'options' => ['as' => 'My Test PDF', 'mime' => 'pdf']] 176 | ], 'attachments', $mailer); 177 | 178 | $mailer->attach([ ['path' => '/public/pdf/test3.pdf', 'options' => ['as' => 'My Test PDF']], ['path' => '/public/pdf/test4.pdf'] ]); 179 | $this->assertAttributeEquals( 180 | [ 181 | 0 => ['path' => '/public/pdf/test1.pdf', 'options' => []], 182 | 1 => ['path' => '/public/pdf/test2.pdf', 'options' => ['as' => 'My Test PDF', 'mime' => 'pdf']], 183 | 2 => ['path' => '/public/pdf/test3.pdf', 'options' => ['as' => 'My Test PDF']], 184 | 3 => ['path' => '/public/pdf/test4.pdf', 'options' => []] 185 | ], 'attachments', $mailer); 186 | 187 | } 188 | 189 | public function testSettingLayoutPropertiesInSwiftMailer() 190 | { 191 | $layout = $this->getLayoutMock(); 192 | $layout->shouldReceive('setViewLayout')->zeroOrMoreTimes(); 193 | $layout->shouldReceive('setViewTemplate')->zeroOrMoreTimes(); 194 | $layout->shouldReceive('includeVariables')->zeroOrMoreTimes(); 195 | $layout->shouldReceive('clearVariables')->once(); 196 | 197 | $mailer = new IlluminateMailer($this->getMailerMock(), $layout, $this->getConfigMock(), $this->getLoggerMock()); 198 | 199 | // Test Setting Layout 200 | $this->assertEquals($mailer, $mailer->layout('emails.layouts.default')); 201 | 202 | // Test Setting Template 203 | $this->assertEquals($mailer, $mailer->template('emails.templates.default')); 204 | 205 | // Test Setting Message Variables 206 | $this->assertEquals($mailer, $mailer->pass(['variableOne' => 'One', 'variableTwo' => 'two'])); 207 | 208 | // Clearing Message Variables 209 | $this->assertEquals($mailer, $mailer->clear()); 210 | } 211 | 212 | private function getMailerMock() 213 | { 214 | return m::mock('Illuminate\Mail\Mailer'); 215 | } 216 | 217 | private function getConfigMock() 218 | { 219 | $config = m::mock('Illuminate\Config\Repository'); 220 | $config->shouldReceive('get')->zeroOrMoreTimes()->andReturn([ 221 | 'to' => [], 222 | 'cc' => [], 223 | 'bcc' => [], 224 | 'replyTo' => [], 225 | 'from' => [], 226 | 'sender' => [], 227 | 'attachments' => [], 228 | 'subject' => 'Pigeon Delivery', 229 | 'layout' => 'emails.layouts.default', 230 | 'template' => 'emails.templates.default', 231 | 'message_variables' => [] 232 | ]); 233 | 234 | return $config; 235 | } 236 | 237 | private function getLayoutMock() 238 | { 239 | $layout = m::mock('Larablocks\Pigeon\MessageLayout'); 240 | $layout->shouldReceive('setViewLayout')->zeroOrMoreTimes(); 241 | $layout->shouldReceive('setViewTemplate')->zeroOrMoreTimes(); 242 | $layout->shouldReceive('includeVariables')->zeroOrMoreTimes(); 243 | 244 | return $layout; 245 | } 246 | 247 | private function getLoggerMock() 248 | { 249 | return m::mock('Illuminate\Log\Writer'); 250 | } 251 | } -------------------------------------------------------------------------------- /tests/MessageLayoutTest.php: -------------------------------------------------------------------------------- 1 | setViewLayout('test.view.layout'); 19 | 20 | $this->assertAttributeEquals('test.view.layout', 'view_layout', $message_layout); 21 | $this->assertEquals('test.view.layout', $message_layout->getViewLayout()); 22 | } 23 | 24 | public function testSettingViewTemplate() 25 | { 26 | $message_layout = new MessageLayout(); 27 | $message_layout->setViewTemplate('test.view.template'); 28 | 29 | $this->assertAttributeEquals('test.view.template', 'view_template', $message_layout); 30 | $this->assertEquals('test.view.template', $message_layout->getViewTemplate()); 31 | } 32 | 33 | public function testAddingAndClearingMessageVariables() 34 | { 35 | $message_layout = new MessageLayout(); 36 | $message_layout->setViewTemplate('test.view.template'); 37 | 38 | $message_layout->includeVariables(['key' => 'value']); 39 | 40 | // Test Setting Variables 41 | $this->assertAttributeEquals(['key' => 'value', $message_layout::TEMPLATE_VARIABLE => 'test.view.template'], 'message_variables', $message_layout); 42 | $this->assertEquals(['key' => 'value', $message_layout::TEMPLATE_VARIABLE => 'test.view.template'], $message_layout->getMessageVariables()); 43 | 44 | $message_layout->clearVariables(); 45 | 46 | $this->assertAttributeEquals([$message_layout::TEMPLATE_VARIABLE => 'test.view.template'], 'message_variables', $message_layout); 47 | } 48 | 49 | } --------------------------------------------------------------------------------