{"id":19337904,"url":"https://github.com/2amigos/mail-api-service","last_synced_at":"2025-08-01T06:10:38.179Z","repository":{"id":56938180,"uuid":"175455060","full_name":"2amigos/mail-api-service","owner":"2amigos","description":"A microservice to send emails based on templates.","archived":false,"fork":false,"pushed_at":"2019-03-22T07:48:47.000Z","size":685,"stargazers_count":25,"open_issues_count":0,"forks_count":2,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-02T06:21:36.335Z","etag":null,"topics":["api","mail","php","service","slim3"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/2amigos.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-03-13T16:05:33.000Z","updated_at":"2024-12-25T10:50:18.000Z","dependencies_parsed_at":"2022-08-21T06:50:22.837Z","dependency_job_id":null,"html_url":"https://github.com/2amigos/mail-api-service","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2amigos%2Fmail-api-service","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2amigos%2Fmail-api-service/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2amigos%2Fmail-api-service/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2amigos%2Fmail-api-service/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/2amigos","download_url":"https://codeload.github.com/2amigos/mail-api-service/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250352226,"owners_count":21416458,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","mail","php","service","slim3"],"created_at":"2024-11-10T03:15:46.529Z","updated_at":"2025-04-23T01:31:06.947Z","avatar_url":"https://github.com/2amigos.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Mail service\n\n![Mail API Service](assets/mail-service@2x.png)\n\nThe Mail service is an Email microservice that sends emails using [mustache-based]((https://github.com/bobthecow/mustache.php)) \ntemplates. It was built to allow our development teams at [2amigos](https://2amigos.us) to avoid having to configure mail over and over on projects \ninvolving a microservices infrastructure. It's a combination of two separate applications, one being Symfony's CI application and the other being\nan API built with Slim3 as it uses a technique called [spooling](https://symfony.com/doc/current/email/spool.html).  \n\nThe project uses [Monolog](https://github.com/Seldaek/monolog) for logging, [Fractal](http://fractal.thephpleague.com/) as a \nserializer, [Tactitian](https://tactician.thephpleague.com/) as a command bus, [gettext](https://packagist.org/packages/gettext/gettext) \nfor translations, [Basic access authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) and [Json Web Tokens](https://jwt.io/) \nfor authentication (this is optional), and [Zend filter](https://docs.zendframework.com/zend-filter/) for data filtering and validation.    \n\n[Docker compose](https://docs.docker.com/compose/overview/) and [Postman collection](https://www.getpostman.com/) \nfiles are included for easy development, even though `docker` is not strictly necessary for development as you could easily \nuse PHP built-in server.\n\nThe project tries to follow DDD principles. \n\n## Install\n\nInstall the latest version using [composer](https://getcomposer.org/).\n\n``` bash\n$ composer create-project --no-interaction --stability=dev 2amigos/mail-service app\n```\n\nIf you are using it from a private repository (using a github url here as an example).\n\n``` bash \n$ composer create-project --no-interaction --stability=dev 2amigos/mail-service app --repository-url=https://github.com/2amigos/mail-service\n```\n\n## Configuration\n\nThe project uses environment files to configure secrets, for that reason, you must create a file named `.env` at the root \ndirectory of the project. An `.env.example` file has been provided with all required environment values. Modify that file \nand save it as `.env` in the root directory.\n\nBy default, the API application is configured to work under basic authentication processes. It uses an array of users for \nthat purpose but you could easily change that behavior by configuring the `authenticator` option of the [HttpBasicAuthentication middleware](https://github.com/tuupola/slim-basic-auth/blob/3.x/src/HttpBasicAuthentication.php#L43) \nby creating your own or using one provided by the library. Check the [PdoAuthenticator](https://github.com/tuupola/slim-basic-auth/blob/3.x/src/HttpBasicAuthentication/PdoAuthenticator.php). \n\nIf authentication is successful, the action will return a Json Web Token to be used for subsequent calls. \n\nAuthentication, or the usage of scopes are optional. If you don't wish to work with this kind of setup, simply remove \nthe middleware configurations of `HttpBasicAuthentication`, `JwtAuthentication` and `ScopeMiddleware` middlewares.\n\nThe most important part of the application is its `views`, which need to be in the `views/txt` and `views/html` subdirectories.\nTheir names already explain what type of templates should be in each one.\n\nIt also has multi-language support by using `gettext`. An example translation file and template have been provided to help \nyou understand how it works. We have also added a command to work with the excellent localization management platform \ncalled [POEditor](https://poeditor.com/). That command will import for you the translations and transform the files to `.php` \nfiles. To import the required translations to your project from `POEditor` use this command: \n\n``` bash \n$ ./bin/console import-translations:run --api-token={POEDITOR_TOKEN} --project={PROJECT_ID} --languages=es,de --delay=3\n```\n\nWhere {POEDITOR_TOKEN} and {PROJECT_ID} are your token and project id respectively.\n\nThe translations will be automatically imported into the `./i18n/` folder. \n\nIn order to work with translations, we have also included a helper class to work with `Mustache` that will parse the \ncontent and attempt to get the translated content of text within `{{#i18n}}{{/i18n}}` tags. See the example view provided on \nthis project.  \n\n## Usage\n\nFor the sake of the example, go to the `public` folder of the app and start the built-in PHP server like this: \n\n``` bash\nphp -S localhost:8080\n``` \n\nNow we can access the api at `http://127.0.0.1:8080`. \n\n### Get a token \n\nTo get a token, use the following:\n\n``` bash\n$ curl \"https://127.0.0.1:8080/token\" \\\n    --request POST \\\n    --include \\\n    --insecure \\\n    --header \"Content-Type: application/json\" \\\n    --data '[\"mail.all\"]' \\\n    --user test:test\n\nHTTP/1.1 201 Created\nContent-Type: application/json\n\n{\n    \"data\": {\n        \"token\": \"XXXXXXXXXX\",\n        \"expires\": 1550271641\n    }\n}\n``` \n\n### Sending an email (to the spool)\n\nUsing the `token`, you can now post a request using `application/form-data` to send an email. \n\n``` bash \n\ncurl -X POST \\\n  http://127.0.0.1:8080/mail/send \\\n  -H 'Authorization: Bearer YOUR_TOKEN_HERE' \\\n  -H 'Cache-Control: no-cache' \\\n  -H 'Content-Type: application/x-www-form-urlencoded' \\\n  -H 'Postman-Token: 22bf2715-35e4-41ee-a04b-fd8beddcdd62' \\\n  -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \\\n  -F from=noreply@example.com \\\n  -F to=user@example.com \\\n  -F 'subject=Testing micro-services' \\\n  -F template=hello-world \\\n  -F 'data[name]=World' \\\n  -F language=es \\\n  -F 'attachments[]=@/path/to/image/to/attach/41835188_10217308479844850_6484466208170049536_o.jpg'\n  \n```\n\nThe above command will create an email message on the spool directory, configured by default at the `runtime` folder. \n\n#### Parameters \n\n- `from`: Optional. Who the message is from. If not specified, the mail message will be configured with the \nenvironment variable named `MAIL_NO_REPLY_EMAIL` (see `.env.example` file).\n- `to`: Required. To whom the message was addressed. \n- `subject`: Required. This is what the sender set as the topic of the email content. \n- `template`: Required. The name of the template. For example, if we set this parameter with the value `registration`, \nthe system will validate whether a mustache template with the name `registration.mustache` can be found in either \nthe `views/txt` or `views/html` folders. \n- `language`: Optional. If the name is translated, set this parameter with the language code you wish to have the message\ntranslated to. For example, if you set it to `es`, it will try to load the translations from the `i18n/es/messages.php` file. \nSee `src\\Infrastructure\\Mustache\\Helpers\\TranslatorHelper` for further information on loading translations. \n\n\n### Sending an email (from the spool)\n\nWe use [Symfony's SwiftMailer bundle](https://github.com/symfony/swiftmailer-bundle) to ease the task of sending emails \nfrom the spool as it comes with some handy commands. From the project root type `$ ./bin/console` on the terminal and \nthe following commands will be shown: \n\n``` bash \nAvailable commands:\n  about                      Displays information about the current project\n  help                       Displays help for a command\n  list                       Lists commands\n assets\n  assets:install             Installs bundles web assets under a public directory\n cache\n  cache:clear                Clears the cache\n  cache:pool:clear           Clears cache pools\n  cache:pool:delete          Deletes an item from a cache pool\n  cache:pool:prune           Prunes cache pools\n  cache:warmup               Warms up an empty cache\n config\n  config:dump-reference      Dumps the default configuration for an extension\n debug\n  debug:autowiring           Lists classes/interfaces you can use for autowiring\n  debug:config               Dumps the current configuration for an extension\n  debug:container            Displays current services for an application\n  debug:event-dispatcher     Displays configured listeners for an application\n  debug:router               Displays current routes for an application\n  debug:swiftmailer          Displays current mailers for an application\n enqueue\n  enqueue:consume            [enq:c] A client's worker that processes messages. By default it connects to default queue. It select an appropriate message processor based on a message headers\n  enqueue:produce            Sends an event to the topic\n  enqueue:routes             [debug:enqueue:routes] A command lists all registered routes.\n  enqueue:setup-broker       [enq:sb] Setup broker. Configure the broker, creates queues, topics and so on.\n  enqueue:transport:consume  A worker that consumes message from a broker. To use this broker you have to explicitly set a queue to consume from and a message processor service\n import-translations\n  import-translations:run    Import POEditor translations command\n lint\n  lint:yaml                  Lints a file and outputs encountered errors\n router\n  router:match               Helps debug routes by simulating a path info match\n swiftmailer\n  swiftmailer:email:send     Send simple email message\n  swiftmailer:spool:send     Sends emails from the spool\n``` \n\nTo send emails from the spool, simply configure a cron job on your server to run the following command at whatever \ntime interval you think is best for your application: \n\n``` bash \n$ ./bin/console swiftmailer:spool:send --message-limit=10\n```\n\nNow, we have to say that whilst `spooling` is a great feature from `SwiftMailer`, this technique is not suitable for \napplications that require sending a high volume of emails. In that case, we highly recommend the usage of a good queue \nlibrary such as [php-enqueue](https://enqueue.forma-pro.com/) with the broker that best suits your knowledge and requirements. \nWe recommend `RabbitMQ` as it comes with a manager interface where you will be able to see things such as how many emails \nare being sent, how many have failed, and so on, with the ease of adding/removing as many workers as you need under a possible heavy load. \nIt is also `open source`. \n\nWe have provided a working example using [php-enqueue/enqueue-bundle](https://github.com/php-enqueue/enqueue-bundle) which \ncomes with a set of very handy commands so you don't need to replicate that work, in conjunction with its \n[Filesystem transport](https://github.com/php-enqueue/fs). The following sections explain how to work with that queue \nsystem provided.  \n\n### Sending an email (to the filesystem queue)\n\nFirst what we need to do is to modify the `commandBus` locator map and use the `mail.send.queue.handler` instead of \n`mail.send.spool.handler`: \n\n``` php \n $map = [\n         CreateTokenCommand::class =\u003e 'token.create.handler',\n         SendMessageCommand::class =\u003e 'mail.send.queue.handler', // must be set like this\n     ];\n ```\n\nAnd that's it. Using the same previous call, this time the message will be sent to the configured queue on the runtime \nfolder. \n\n### Sending an email (from the filesystem queue)\n\nAs we said previously, the [php-enqueue/enqueue-bundle](https://github.com/php-enqueue/enqueue-bundle) comes with a set \nof pretty handy commands. For the full reference of those commands, please go to [its documentation](https://github.com/php-enqueue/enqueue-dev/blob/master/docs/bundle/cli_commands.md). \n\nThe one to consume all the messages that go to the queue is `enqueue:consume`: \n\n``` bash \n$ ./bin/console enqueue:consume mail --no-interaction -vvv --receive-timeout=60000 \n``` \n\n### Using the best of both worlds \n\nThe library also comes with a custom spool so you can use [php-enqueue](https://enqueue.forma-pro.com/) with Swiftmailer. \n\nIn order to use it you will have to make some changes on the code: \n\n#### Modify mail.send.spool.handler\n\nWe need to use the already configured `SendMesssageSpoolHandler` to use our custom `EnqueueSpool` component on the \n`./config/api/dependencies.php` file:\n\n``` php \n$container['mail.send.spool.handler'] = function ($container) {\n    return new SendMessageSpoolHandler(\n        $container['enqueue.mailer'], // \u003c--- here is the modification\n        $container['mustache'],\n        $container['mustache.i18n.helper'],\n        $container['fs']\n    );\n};\n\n```\n\n#### Modify services.yaml\n\nThen on `./config/console/services.yaml`, we should refactor the file and make it look like this: \n\n``` yaml \n\nswiftmailer.mailer.spool_mailer.spool.custom:\n        class: App\\Infrastructure\\SwiftMailer\\EnqueueSpool \n        arguments:\n           $context: @enqueue.fs.context\n           $queue: 'enqueue.app.mail'\n           \n        # class: App\\Infrastructure\\SwitftMailer\\FileSpool # commented setting! \n        # arguments:\n        #   $path: '%kernel.project_dir%/runtime/spool/default'\n\n    enqueue.mail.processor:\n        class: App\\Application\\Console\\Processor\\SendMailProcessor\n        public: true\n        arguments:\n            $mailer: '@swiftmailer.mailer.enqueue_mailer'\n            $mustache: '@mustache.engine.mail'\n            $translatorHelper: '@mustache.i18n.helper'\n        tags:\n            - { name: 'enqueue.processor', command: '__command__', processorName: 'mail' }\n\n    enqueue.fs.context: \n        class: Enqueue\\Fs\\FsContext\n        arguments:\n            $storeDir: '%kernel.project_dir%/runtime/queue'\n            $preFetchCount: 1\n            $chmod: 600\n            $pollingInterval: 100\n\n\n```\n\nThat's it, the way to use it simply follow the guidelines of `sending an email from/to the spool` above.\n\n## Contributing \n\nTo contribute, please read our [CONTRIBUTION guidelines](CONTRIBUTING.md).\n\n## Credits\n\n- [Tuupola slim api skeleton](https://github.com/tuupola/slim-api-skeleton) Thanks for the boilerplate inspiration!\n- [2amigos](https://2amigos.us)\n- [All Contributors](../../contributors)\n\n## License\n\nThe BSD License (BSD). Please see [License File](LICENSE.md) for more information.\n\n\u003e [![2amigOS!](https://s.gravatar.com/avatar/55363394d72945ff7ed312556ec041e0?s=80)](http://www.2amigos.us)  \n\u003e \u003ci\u003eBeyond Software\u003c/i\u003e  \n\u003e [www.2amigos.us](http://www.2amigos.us)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F2amigos%2Fmail-api-service","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F2amigos%2Fmail-api-service","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F2amigos%2Fmail-api-service/lists"}