From 655ffce9234c78cbe7e8c86287ee16d909a652d0 Mon Sep 17 00:00:00 2001 From: Maxime Renou Date: Wed, 8 Jun 2022 14:41:57 +0200 Subject: [PATCH] feat: mail templates package --- .gitignore | 3 + README.md | 138 +++++++ composer.json | 41 ++ composer.lock | 679 +++++++++++++++++++++++++++++++ config/mail_templates.php | 23 ++ src/MailTemplate.php | 213 ++++++++++ src/MailTemplatesChannel.php | 28 ++ src/MailTemplatesException.php | 5 + src/MailTemplatesServiceProvider.php | 39 ++ src/Providers/BluesquareMailProvider.php | 8 + src/Providers/LogsProvider.php | 24 ++ src/Providers/SendinblueProvider.php | 74 ++++ src/Providers/TemplateMailProvider.php | 12 + 13 files changed, 1287 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 config/mail_templates.php create mode 100644 src/MailTemplate.php create mode 100644 src/MailTemplatesChannel.php create mode 100644 src/MailTemplatesException.php create mode 100644 src/MailTemplatesServiceProvider.php create mode 100644 src/Providers/BluesquareMailProvider.php create mode 100644 src/Providers/LogsProvider.php create mode 100644 src/Providers/SendinblueProvider.php create mode 100644 src/Providers/TemplateMailProvider.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea6d64f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +/vendor +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ee2b927 --- /dev/null +++ b/README.md @@ -0,0 +1,138 @@ +# Mail Templates + +Ce package Laravel permet d'envoyer des templates mail via Sendinblue, Bluesquare Mail, et d'autres fournisseurs au besoin. + +## Installation + +Ajouter à `composer.json` : + +``` +"require": { + "bluesquare/laravel-mail-templates": "^1.0" +}, +"repositories": [ + { + "type": "vcs", + "url": "https://git.bluesquare.io/bluesquare/laravel-mail-templates" + } +] +``` + +Puis installer le package ainsi : + +```bash +composer update bluesquare/laravel-mail-templates +``` + +## Configuration + +Par défaut, ces variables sont indispensables dans le `.env`: + +```dotenv +MAIL_TEMPLATES_PROVIDER=sendinblue +MAIL_TEMPLATES_API_KEY=your_api_key +``` + +Par défaut, `MAIL_FROM_NAME` et `MAIL_FROM_ADDRESS` sont utilisés pour l'expéditeur, mais peuvent être personnalisés ainsi : + +```dotenv +MAIL_TEMPLATES_FROM_NAME="Bluesquare" +MAIL_TEMPLATES_FROM_ADDRESS="contact@bluesquare.io" +``` + +Il est aussi possible d'utiliser un endpoint personnalisé pour le provider choisi : + +```dotenv +MAIL_TEMPLATES_API_URL=http://laravel.test/api/mails/template +``` + +## Utilisation + +Créer une notification : + +```bash +php artisan make:notification MyAwesomeNotification +``` + +Ajouter `MailTemplatesChannel` dans la méthode `via()` : + +```php +return [MailTemplatesChannel::class]; +``` + +Ajouter une méthode 'toTemplate()', en spécifiant le template et les paramètres souhaités : + +```php +public function toTemplate($notifiable) +{ + return (new MailTemplate('invoice-available')) + ->addParameter('price', '$100'); +} +``` + +Exemple avancé : + +```php +public function toTemplate($notifiable) +{ + return (new MailTemplate("my-template-name")) + ->sender("john.doe@gmail.com", "John OPTIONAL") // OPTIONAL + ->replyTo("jean.grey@gmail.com", "Jean OPTIONAL") // OPTIONAL + ->recipients([ + [ + "elvis@gmail.com", + [ + "name" => "Elvis" // OPTIONAL, + "parameters" => ["key" => "value"] // OPTIONAL + ] + ], + [ + "robert@gmail.com" + ] + ]) + ->addRecipient("edward@gmail.com") // OPTIONAL + ->parameters(["key" => "value", "key" => "value"]) // OPTIONAL + ->addParameter("key", "value") // OPTIONAL + ; +} +``` + +> Le `$notifiable` est automatiquement ajouté comme destinataire. + +## Mapping + +Lors d'une transition d'un provider à l'autre, les ID / noms de templates peuvent varier. +Pour cette raison, il est possible de mapper les templates selon le provider. + +Avant tout, publier le fichier de config via : + +```bash +php artisan vendor:publish +``` + +Ensuite, mapper les templates dans `config/mail_templates.php` : + +```php +'map' => [ + 'sendinblue' => [ + // Nom utilisé dans la notification => ID réel du template sur Sendinblue + 'template-1' => '1', + 'template-2' => '3', + ], + //... +] +``` + +## Tests + +Il est possible de rediriger tous les mails vers une adresse : + +```dotenv +MAIL_TEMPLATES_REDIRECT="contact@bluesquare.io" +``` + +Ou de logger les templates au lieu de les envoyer : + +```dotenv +MAIL_TEMPLATES_PROVIDER=logs +``` \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..8d630f6 --- /dev/null +++ b/composer.json @@ -0,0 +1,41 @@ +{ + "name": "bluesquare/laravel-mail-templates", + "description": "Send mail templates from your Laravel notifications.", + "keywords": [ + "package", + "mail", + "api", + "template", + "email" + ], + "homepage": "https://git.bluesquare.io/bluesquare/laravel-mail-templates", + "license": "proprietary", + "authors": [ + { + "name": "Bluesquare", + "email": "contact@bluesquare.io", + "homepage": "https://bluesquare.io/", + "role": "Developers" + } + ], + "minimum-stability": "dev", + "autoload": { + "psr-4": { + "Bluesquare\\MailTemplates\\": "src/" + } + }, + "extra": { + "laravel": { + "providers": [ + "Bluesquare\\MailTemplates\\MailTemplatesServiceProvider" + ] + } + }, + "require": { + "guzzlehttp/guzzle": "^7.0.1", + "php": "^7.3 | ^8.0", + "sendinblue/api-v3-sdk": "8.x.x", + "ext-json": "*" + }, + "prefer-stable": true +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..9e6c749 --- /dev/null +++ b/composer.lock @@ -0,0 +1,679 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "162723903a241fbba3c0a8abad56fe40", + "packages": [ + { + "name": "guzzlehttp/guzzle", + "version": "7.4.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "74a8602c6faec9ef74b7a9391ac82c5e65b1cdab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/74a8602c6faec9ef74b7a9391ac82c5e65b1cdab", + "reference": "74a8602c6faec9ef74b7a9391ac82c5e65b1cdab", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5", + "guzzlehttp/psr7": "^1.8.3 || ^2.1", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "ext-curl": "*", + "php-http/client-integration-tests": "^3.0", + "phpunit/phpunit": "^8.5.5 || ^9.3.5", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.4-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.4.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2022-05-25T13:24:33+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da", + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2021-10-22T20:56:57+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "c94a94f120803a18554c1805ef2e539f8285f9a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/c94a94f120803a18554c1805ef2e539f8285f9a2", + "reference": "c94a94f120803a18554c1805ef2e539f8285f9a2", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.2.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2022-03-20T21:55:58+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client/tree/master" + }, + "time": "2020-06-29T06:28:15+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "sendinblue/api-v3-sdk", + "version": "v8.2.1", + "source": { + "type": "git", + "url": "https://github.com/sendinblue/APIv3-php-library.git", + "reference": "74d4b0ffb1cfc377a3744291de206122fcf5ed37" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sendinblue/APIv3-php-library/zipball/74d4b0ffb1cfc377a3744291de206122fcf5ed37", + "reference": "74d4b0ffb1cfc377a3744291de206122fcf5ed37", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "guzzlehttp/guzzle": "^7.4.0", + "php": ">=5.6" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~1.12", + "phpunit/phpunit": "^4.8", + "squizlabs/php_codesniffer": "~2.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.x.x-dev" + } + }, + "autoload": { + "psr-4": { + "SendinBlue\\Client\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "SendinBlue Developers", + "email": "contact@sendinblue.com", + "homepage": "https://www.sendinblue.com/" + } + ], + "description": "Official SendinBlue provided RESTFul API V3 php library", + "homepage": "https://github.com/sendinblue/APIv3-php-library", + "keywords": [ + "api", + "php", + "sdk", + "sendinblue", + "swagger" + ], + "support": { + "issues": "https://github.com/sendinblue/APIv3-php-library/issues", + "source": "https://github.com/sendinblue/APIv3-php-library/tree/v8.2.1" + }, + "time": "2022-04-08T09:10:12+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/26954b3d62a6c5fd0ea8a2a00c0353a14978d05c", + "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c", + "shasum": "" + }, + "require": { + "php": ">=8.0.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:55:41+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": "^7.3 | ^8.0", + "ext-json": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.2.0" +} diff --git a/config/mail_templates.php b/config/mail_templates.php new file mode 100644 index 0000000..a956033 --- /dev/null +++ b/config/mail_templates.php @@ -0,0 +1,23 @@ + [ + 'sendinblue' => [ + //'template-name' => 'sendinblue-template-id', + ], + //... + ], + + 'sender' => [ + 'name' => env('MAIL_TEMPLATES_FROM_NAME', env('MAIL_FROM_NAME', 'Example')), + 'email' => env('MAIL_TEMPLATES_FROM_ADDRESS', env('MAIL_FROM_ADDRESS', 'noreply@example.com')), + ], + + 'provider' => env('MAIL_TEMPLATES_PROVIDER', 'logs'), + + 'api_key' => env('MAIL_TEMPLATES_API_KEY', null), + + 'api_url' => env('MAIL_TEMPLATES_API_URL', null), + + 'redirect' => env('MAIL_TEMPLATES_REDIRECT', null), +]; diff --git a/src/MailTemplate.php b/src/MailTemplate.php new file mode 100644 index 0000000..06260cc --- /dev/null +++ b/src/MailTemplate.php @@ -0,0 +1,213 @@ +templateId = $templateId; + + $this->sender( + config('mail_templates.sender.email'), + config('mail_templates.sender.name') + ); + } + + /** + * @param string $address + * @param string|null $name + * @return MailTemplate + */ + public function sender(string $address, string $name = null): MailTemplate + { + $this->sender['address'] = $address; + + if (! empty($name)) + $this->sender['name'] = $name; + + return $this; + } + + /** + * @param string $address + * @param string|null $name + * @return MailTemplate + */ + public function replyTo(string $address, string $name = null): MailTemplate + { + $this->replyTo['address'] = $address; + + if (! empty($name)) + $this->replyTo['name'] = $name; + + return $this; + } + + /** + * @param array $recipients + * @return MailTemplate + */ + public function recipients(array $recipients): MailTemplate + { + if (!empty($recipients)) { + foreach ($recipients as $recipient) { + if (!empty($recipient[0]) && is_string($recipient[0])) { + $data = [ + 'address' => $recipient[0] + ]; + + if (!empty($recipient[1])) { + if (!empty($recipient[1]['name'])) + $data['name'] = $recipient[1]['name']; + + if (!empty($recipient[1]['parameters'])) + $data['parameters'] = $recipient[1]['parameters']; + } + + $this->recipients[] = $data; + } + } + } + + return $this; + } + + /** + * @param string $address + * @param array $informations + * @return MailTemplate + */ + public function addRecipient(string $address, array $informations = []): MailTemplate + { + $data = [ + 'address' => $address + ]; + + if (!empty($informations)) { + if (!empty($informations['name'])) + $data['name'] = $informations['name']; + + if (!empty($informations['parameters'])) + $data['parameters'] = $informations['parameters']; + } + + $this->recipients[] = $data; + return $this; + } + + /** + * @param array $parameters + * @return MailTemplate + */ + public function parameters(array $parameters): MailTemplate + { + $this->parameters = $parameters; + return $this; + } + + /** + * @param array $attachments + * @return MailTemplate + */ + public function attachments(array $attachments): MailTemplate + { + foreach ($attachments as $attachment) { + $this->addAttachment($attachment['path'] ?? $attachment['file'], $attachment['filename'] ?? null); + } + + return $this; + } + + public function addAttachment($file, $filename = null) + { + $file = is_object($file) && method_exists($file, 'getRealPath') ? $file->getRealPath() : $file; + + $this->attachments[] = [ + 'path' => $file, + 'filename' => $filename ?? basename($file) + ]; + + return $this; + } + + /** + * @param string $key + * @param string $value + * @return MailTemplate + */ + public function addParameter(string $key, string $value): MailTemplate + { + $this->parameters[$key] = $value; + return $this; + } + + /** + * Get an array representation of the message. + * + * @return array + */ + public function toArray(): array + { + return [ + 'templateId' => $this->templateId, + 'sender' => $this->sender, + 'replyTo' => $this->replyTo, + 'recipients' => $this->recipients, + 'attachments' => $this->attachments, + 'parameters' => $this->parameters, + ]; + } + + public function jsonSerialize(): mixed + { + return $this->toArray(); + } +} diff --git a/src/MailTemplatesChannel.php b/src/MailTemplatesChannel.php new file mode 100644 index 0000000..2a83a78 --- /dev/null +++ b/src/MailTemplatesChannel.php @@ -0,0 +1,28 @@ +provider = $provider; + } + + /** + * @param $notifiable + * @param Notification $notification + * @throws MailTemplatesException + */ + public function send($notifiable, Notification $notification) + { + $template = $notification->toTemplate($notifiable); + + $this->provider->send($template, $notifiable); + } +} diff --git a/src/MailTemplatesException.php b/src/MailTemplatesException.php new file mode 100644 index 0000000..6755b6c --- /dev/null +++ b/src/MailTemplatesException.php @@ -0,0 +1,5 @@ +mergeConfigFrom( + __DIR__ . '/../config/mail_templates.php', + 'mail_templates' + ); + + $this->app->singleton(TemplateMailProvider::class, function ($app) { + $config = config('mail_templates'); + + switch ($config['provider']) { + case 'logs': return new LogsProvider($config); + case 'sendinblue': return new SendinblueProvider($config); + case 'bluesquare': return new BluesquareMailProvider($config); + } + + throw new MailTemplatesException("Unknown provider {$config['provider']}"); + }); + } + + public function boot() + { + $this->publishes([ + __DIR__ . '/../config/mail_templates.php' => config_path('mail_templates.php') + ], 'config'); + } +} diff --git a/src/Providers/BluesquareMailProvider.php b/src/Providers/BluesquareMailProvider.php new file mode 100644 index 0000000..598665c --- /dev/null +++ b/src/Providers/BluesquareMailProvider.php @@ -0,0 +1,8 @@ +config = $config; + } + + public function send(MailTemplate $template, $notifiable = null) + { + Log::debug("Mail Templates: send()", [ + 'template' => $template->toArray(), + 'notifiable' => $notifiable + ]); + } +} \ No newline at end of file diff --git a/src/Providers/SendinblueProvider.php b/src/Providers/SendinblueProvider.php new file mode 100644 index 0000000..657ae57 --- /dev/null +++ b/src/Providers/SendinblueProvider.php @@ -0,0 +1,74 @@ +config = $config; + + $api_config = \SendinBlue\Client\Configuration::getDefaultConfiguration() + ->setApiKey('api-key', $config['api_key']); + + if (! empty($config['api_url'])) + $api_config->setHost($config['api_url']); + + $this->api = new TransactionalEmailsApi( + new \GuzzleHttp\Client(), + $api_config + ); + } + + public function send(MailTemplate $template, $notifiable = null) + { + $data = $template->toArray(); + + $model = new SendSmtpEmail(); + + $template = $data['templateId']; + + if (isset($config['map']['sendinblue']) && $config['map']['sendinblue'][$template]) { + $template = $config['map']['sendinblue'][$template]; + } + + $model->setTemplateId($template); + $model->setParams($data['parameters']); + + $model->setSender(new SendSmtpEmailSender($data['sender'])); + + if ($data['replyTo']) + $model->setReplyTo(new SendSmtpEmailReplyTo($data['replyTo'])); + + $model->setTo(array_map(function ($to) { + return new SendSmtpEmailTo($to); + }, $data['recipients'])); + + if (! empty($config['redirect'])) + $model->setTo([ + new SendSmtpEmailTo([ + 'email' => $config['redirect'] + ]) + ]); + + $model->setAttachment(array_map(function ($item) { + $attachment = new SendSmtpEmailAttachment(); + $attachment->setName($item['filename']); + $attachment->setContent(file_get_contents($item['path'])); + return $attachment; + }, $data['attachments'])); + + $this->api->sendTransacEmail($model); + } +} \ No newline at end of file diff --git a/src/Providers/TemplateMailProvider.php b/src/Providers/TemplateMailProvider.php new file mode 100644 index 0000000..6b1eeff --- /dev/null +++ b/src/Providers/TemplateMailProvider.php @@ -0,0 +1,12 @@ +