{"id":15043083,"url":"https://github.com/ozimov/spring-boot-email-tools","last_synced_at":"2025-04-04T16:16:50.515Z","repository":{"id":44729685,"uuid":"44586882","full_name":"ozimov/spring-boot-email-tools","owner":"ozimov","description":"A set of services and tools for sending emails in a Spring Boot 1.5.x application using a Template Engine","archived":false,"fork":false,"pushed_at":"2023-12-04T09:44:05.000Z","size":816,"stargazers_count":197,"open_issues_count":15,"forks_count":95,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-03-28T15:09:58.791Z","etag":null,"topics":["email-sender","email-template","freemarker","java-8","mustache","pebble","redis","spring-boot","template-engine","thymeleaf"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ozimov.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-10-20T06:33:43.000Z","updated_at":"2025-02-25T10:10:31.000Z","dependencies_parsed_at":"2024-10-12T15:50:47.071Z","dependency_job_id":null,"html_url":"https://github.com/ozimov/spring-boot-email-tools","commit_stats":null,"previous_names":["robertotru/spring-boot-email-tools"],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ozimov%2Fspring-boot-email-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ozimov%2Fspring-boot-email-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ozimov%2Fspring-boot-email-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ozimov%2Fspring-boot-email-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ozimov","download_url":"https://codeload.github.com/ozimov/spring-boot-email-tools/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247208183,"owners_count":20901570,"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":["email-sender","email-template","freemarker","java-8","mustache","pebble","redis","spring-boot","template-engine","thymeleaf"],"created_at":"2024-09-24T20:48:32.852Z","updated_at":"2025-04-04T16:16:50.491Z","avatar_url":"https://github.com/ozimov.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spring Boot Email Tools\nA set of services and tools for sending emails in a **Spring Boot** application using plain text, html or\na template engine to generate dynamic content.\n\n**Source Website:** *[github.com/ozimov/spring-boot-email-tools](http://github.com/ozimov/spring-boot-email-tools/)*\u003cbr /\u003e\n\n**Latest Release:** *1.0.0* \u003cbr /\u003e\n**Latest Artifacts:** *it.ozimov:spring-boot-email-core*, *it.ozimov:spring-boot-freemarker-email*,\n    *it.ozimov:spring-boot-mustache-email*, *it.ozimov:spring-boot-pebble-email*, *it.ozimov:spring-boot-thymeleaf-email* \u003cbr /\u003e\n**Continuous Integration:** \u003cbr /\u003e\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/it.ozimov/spring-boot-email-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.ozimov/spring-boot-email-core)\n\u003cbr /\u003e\n[![Build Status](https://travis-ci.org/ozimov/spring-boot-email-tools.svg?branch=master)](https://travis-ci.org/ozimov/spring-boot-email-tools)\n[![codecov.io](https://codecov.io/github/ozimov/spring-boot-email-tools/coverage.svg?branch=master)](https://codecov.io/github/ozimov/spring-boot-email-tools?branch=master)\n[![Codacy Badge](https://api.codacy.com/project/badge/grade/7a4364b93df6473fb18a597e900edceb)](https://www.codacy.com/app/roberto-trunfio/spring-boot-email-tools)\n\n![codecov.io](https://codecov.io/github/ozimov/spring-boot-email-tools/branch.svg?branch=master)\n\n\n## Background\n\nThe project relies on a templateless module `it.ozimov:spring-boot-email-core` that provides the core\nfeatures (e.g. sending emails, scheduling and prioritizing, persistence). Since it is templateless, it  does not provide\n any implementation of the service to be used to generate the body of the email via template engine.\n\nIf you want to use one of the template engines supported by this project (i.e. _Freemarker_,\n_Mustache_, _Pebble_ and _Thymeleaf_), you can use the dedicated templatefull\nmodule that is shipped with the core module. The standard naming for the templatefull module is\n`it.ozimov:spring-boot-{template_engine_name}-email` (where `{template_engine_name}` is for instance `pebble`).\n\n## Dependency\nLatest release is **`1.0.0`**. To use the core module, you can import the following dependency in Maven\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eit.ozimov\u003c/groupId\u003e\n    \u003cartifactId\u003espring-boot-email-core\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nTo embed the module that includes the _Freemarker_ template engine, you can use the following Maven dependency:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eit.ozimov\u003c/groupId\u003e\n    \u003cartifactId\u003espring-boot-freemarker-email\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nfor _Mustache_:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eit.ozimov\u003c/groupId\u003e\n    \u003cartifactId\u003espring-boot-mustache-email\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nfor _Pebble_:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eit.ozimov\u003c/groupId\u003e\n    \u003cartifactId\u003espring-boot-pebble-email\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nand for _Thymeleaf_:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eit.ozimov\u003c/groupId\u003e\n    \u003cartifactId\u003espring-boot-thymeleaf-email\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nRemember that if you import the template-full module, the core module should not be required.\n\n\n## Usage\nIn your main Spring Boot application, you need to add the annotation `@EnableEmailTools` to\n  enable support for all the services and controllers defined in the Spring Boot Email module, e.g.:\n\n```java\n@SpringBootApplication\n@EnableEmailTools\npublic class MainApplication  {\n\n    public static void main(final String ... args) {\n        SpringApplication.run(MainApplication.class, args);\n    }\n}\n```\n\nin you `application.properties` set the configuration needed to send the emails, e.g. if you want to send\nthe emails using a Gmail account you can set:\n\n```properties\nspring.mail.host=smtp.gmail.com\nspring.mail.port=587\nspring.mail.username=name.surname@gmail.com\nspring.mail.password=V3ry_Str0ng_Password\nspring.mail.properties.mail.smtp.auth=true\nspring.mail.properties.mail.smtp.starttls.enable=true\nspring.mail.properties.mail.smtp.starttls.required=true\n```\n\nPlus, the additional properties must be added to prevent using the persistence layer\n```properties\nspring.mail.scheduler.persistence.enabled=false\nspring.mail.scheduler.persistence.redis.embedded=false\nspring.mail.scheduler.persistence.redis.enabled=false\n```\n\nTo send an email, use the ``EmailService`` in your Spring Boot application. E.g.\n\n\n```java\n@Autowired\npublic EmailService emailService;\n\npublic void sendEmailWithoutTemplating(){\n   final Email email = DefaultEmail.builder()\n        .from(new InternetAddress(\"cicero@mala-tempora.currunt\", \"Marco Tullio Cicerone \"))\n        .to(Lists.newArrayList(new InternetAddress(\"titus@de-rerum.natura\", \"Pomponius Attĭcus\")))\n        .subject(\"Laelius de amicitia\")\n        .body(\"Firmamentum autem stabilitatis constantiaeque eius, quam in amicitia quaerimus, fides est.\")\n        .encoding(\"UTF-8\").build();\n\n   emailService.send(email);\n}\n```\n\n\nThe previous code will send a plain text message. To obtain some more dynamic fancy emails, you have two options:\n_i)_ the former and easier-to-use is to use a templatefull module (e.g. based on Freemarker);\n_ii)_ the latter (which requires some effort on your side) needs an implementation of the\ninterface **`it.ozimov.springboot.templating.mail.service.TemplateService`**.\n\nThe aforementioned interface requires a component that implements the following method\n\n```java\nString mergeTemplateIntoString(String templateReference, Map\u003cString, Object\u003e model)\n            throws IOException, TemplateException;\n```\n\nAssuming you opted for one of the previous options, just put the template in the required folder\n (e.g. ``templates`` under ``resourses``) and try to execute the following code (it works with _Freemarker_):\n\n```java\n@Autowired\npublic EmailService emailService;\n\npublic void sendEmailWithTemplating(){\n   Arrays.asList(new Cospirator(\"cassius@sic-semper.tyrannis\", \"Gaius Cassius Longinus\"),\n            new Cospirator(\"brutus@sic-semper.tyrannis\", \"Marcus Iunius Brutus Caepio\"))\n        .stream.forEach(tyrannicida -\u003e {\n       final Email email = DefaultEmail.builder()\n            .from(new InternetAddress(\"divus.iulius@mala-tempora.currunt\", \"Gaius Iulius Caesar\"))\n            .to(Lists.newArrayList(new InternetAddress(tyrannicida.getEmail(), tyrannicida.getName())))\n            .subject(\"Idus Martii\")\n            .body(\"\")//Empty body\n            .encoding(\"UTF-8\").build();\n        //Defining the model object for the given Freemarker template\n        final Map\u003cString, Object\u003e modelObject = new HashMap\u003c\u003e();\n        modelObject.put(\"tyrannicida\", tyrannicida.getName());\n\n       emailService.send(email, \"idus_martii.ftl\", modelObject);\n   };\n}\n\nprivate static class Cospirator {\n  private String email;\n  private String name;\n  public Cospirator(final String email, final String name){\n    this.email = email;\n    this.name = name;\n  }\n\n  //getters\n}\n```\n\nwhere the template ``idus_martii.ftl`` is a _Freemarker_ file like:\n\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\n\t\u003cbody\u003e\n\t\t\u003cp\u003e\n\t\t\tTu quoque, \u003cem\u003e${tyrannicida}\u003c/em\u003e!\n\t\t\u003c/p\u003e\n\t\u003c/body\u003e\n\u003c/html\u003e\n```\n\n\nThe following example shows how to send and email that includes an inline image.\n\n\n```java\n@Autowired\npublic EmailService emailService;\n\npublic void sendEmailWithTemplatingAndInlineImage(){\n       final Email email = DefaultEmail.builder()\n            .from(new InternetAddress(\"divus.iulius@mala-tempora.currunt\", \"Gaius Iulius Caesar\"))\n            .to(Lists.newArrayList(new InternetAddress(\"brutus@sic-semper.tyrannis\", \"Marcus Iunius Brutus Caepio\")))\n            .subject(\"Idus Martii\")\n            .body(\"\")//Empty body\n            .encoding(\"UTF-8\").build();\n       //Defining the model object for the given Freemarker template\n       final Map\u003cString, Object\u003e modelObject = new HashMap\u003c\u003e();\n       final File imageFile = //load your picture here, e.g. \"my_image.jpg\"\n       modelObject.put(\"tyrannicida\", tyrannicida.getName());\n\n       final InlinePicture inlinePicture = DefaultInlinePicture.builder()\n                               .file(imageFile)\n                               .imageType(ImageType.JPG)\n                               .templateName(\"my_image.jpg\").build());\n\n       emailService.send(email, \"idus_martii.ftl\", modelObject, inlinePicture);\n}\n```\n\nwhere the template ``idus_martii.ftl`` is a Freemarker file like:\n\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\n\t\u003cbody\u003e\n\t\t\u003cp\u003e\n\t\t\t\u003cimg src=\"my_image.jpg\" /\u003e\n\t\t\u003c/p\u003e\n\t\u003c/body\u003e\n\u003c/html\u003e\n```\n\nbe sure that the name provided in the ``InlinePicture`` matches with the one used in the template file path included, if\nany was set. This means that if in the template you have ``\u003cimg src=\"images/my_image.jpg\" /\u003e`` then the definition has to be\nchanged as follows:\n\n```java\nfinal InlinePicture inlinePicture = DefaultInlinePicture.builder()\n        .file(imageFile)\n        .imageType(ImageType.JPG)\n        .templateName(\"images/my_image.jpg\").build());\n```\n\nThis is required to set the a proper content-id.\n\n## Email scheduling\n\nThe library supports email scheduling, but since version _1.0.0_ the scheduler is disabled by default. To enable \nemail scheduling, the following property has to be provided:\n \n```properties\nspring.mail.scheduler.enabled=true\n```\n\nEmail can be set in different queues, from the one with\n highest priority to the least important. Priority 1 is the highest.\n\nTo define the number of priority levels to be used in the scheduler, \njust add in the `application.properties` the following line:\n\n```properties\nspring.mail.scheduler.priorityLevels=5\n```\n\nIf not provided, by default 10 priority levels are considered.\n\nScheduling an email is actually easy and the `EmailSchedulerService` allows to schedule an email with or without\nthe use of a template engine.\n\nIn order to schedule a plain text email, just create your service (or controller) where you autowire \nthe service `EmailSchedulerService` and call a method `scheduleEmail` defined as in the following example\n\n```java\n@Service\npublic void MyEmailSenderService {\n\n    @Autowired\n    private EmailSchedulerService EmailSchedulerService;\n    \n    \n    public void scheduleEmail() throws CannotSendEmailException {\n        final Email mimeEmail = DefaultEmail.builder()\n                                  .from(new InternetAddress(\"divus.iulius@mala-tempora.currunt\", \"Gaius Iulius Caesar\"))\n                                  .to(Lists.newArrayList(new InternetAddress(tyrannicida.getEmail(), tyrannicida.getName())))\n                                  .subject(\"Idus Martii\")\n                                  .body(\"Sic semper...\")\n                                  .encoding(\"UTF-8\")\n                                  .build();\n        final OffsetDateTime scheduledDateTime = OffsetDateTime.now().plusDays(1);\n        final int priorityLevel = 1;\n      EmailSchedulerService.schedule(mimeEmail, scheduledDateTime, priorityLevel);\n    }\n}\n```\n\nHere we go, by calling schedulerEmail() an email has been scheduled to be sent after one day.\nWhen scheduling emails, observe that **`OffsetDateTime` must be** used with **UTC**, so do not forget to convert it if you\nuse a different zone offset.\n\nTo schedule an email with a template and inline images, just call a new method called `scheduleEmailWithTemplate()`\n\n```java\n@Service\npublic void MyEmailWithTemplateSenderService {\n\n    @Autowired\n    private EmailSchedulerService EmailSchedulerService;\n    \n    \n    public void scheduleEmailWithTemplate() throws CannotSendEmailException {\n        final Email mimeEmail = DefaultEmail.builder()\n                                  .from(new InternetAddress(\"divus.iulius@mala-tempora.currunt\", \"Gaius Iulius Caesar\"))\n                                  .to(Lists.newArrayList(new InternetAddress(tyrannicida.getEmail(), tyrannicida.getName())))\n                                  .subject(\"Idus Martii\")\n                                  .body(\"\")//Empty body\n                                  .encoding(\"UTF-8\")\n                                  .build();\n       //Defining the model object for the given Freemarker template\n       final Map\u003cString, Object\u003e modelObject = new HashMap\u003c\u003e();\n       final File imageFile = //load your picture here, e.g. \"my_image.jpg\"\n       modelObject.put(\"tyrannicida\", tyrannicida.getName());\n\n       final InlinePicture inlinePicture = DefaultInlinePicture.builder()\n                               .file(imageFile)\n                               .imageType(ImageType.JPG)\n                               .templateName(\"my_image.jpg\").build();\n        final OffsetDateTime scheduledDateTime = OffsetDateTime.now().plusDays(1);\n        final int priorityLevel = 1;\n      \n        EmailSchedulerService.schedule(mimeEmail, scheduledDateTime, priorityLevel, \n            \"idus_martii.ftl\", modelObject, inlinePicture);\n    }\n    \n}\n```\n\n## Persistence\nPersistence has been introduced in version `0.4.0`. Persistence is mainly of interest if the scheduler is used, therefore\nit can be enabled only if the scheduler is enabled.\n\nThe persistence layer is optional, thus needs to be activated. The default implementation is fully based on embedded REDIS.\nTo enable the default persistence layer just add the additional properties in your `application.properties` file:\n\n```properties\nspring.mail.scheduler.persistence.enabled=true\nspring.mail.scheduler.persistence.redis.enabled=true\nspring.mail.scheduler.persistence.redis.embedded=true\nspring.mail.scheduler.persistence.redis.host=localhost\nspring.mail.scheduler.persistence.redis.port=6381\nspring.mail.scheduler.persistence.redis.settings=\n```\n\nI recommend to specify in the REDIS settings at least the `appendfilename` and `dir` properties,\nso that you know where the append file is placed and which name it uses. For instance do:\n\n```properties\nspring.mail.scheduler.persistence.redis.settings=appendfilename email_appendonly.aof, dir /Users/your_username/Downloads\n```\n\nBy default we have the setting `appendonly yes` and `appendfsync everysec`. Feel free to override them or fine tune them \naccording with your needs.\n\n\nClearly, you can provide your own persistence layer by implementing the `PersistenceService` interface. You can also\n use your REDIS implementation, but this will require extra coding on your side.\n\n\nObserve that the persistence layer makes the emails being stored to be reloaded on application startup if not yet sent.\nIn particular, the emails are loaded when scheduler is constructed. \n\n###Impact of the Persistence layer on the default priority-based scheduler\nThe default scheduler is `PriorityQueueEmailSchedulerService`, which by default stores everything in memory. Clerarly, having\nthousands email being scheduled, storing everything in memory could drive to a potential `OutOfMemoryException`. \nEnabling the persistence layer should allow to use REDIS for persisting scheduled emails. Anyway, you may want to\ncustomize the behavior of the scheduler when interacting with the persistence layer, you can use the following params:\n\n```properties\nspring.mail.scheduler.persistence.desiredBatchSize=200\nspring.mail.scheduler.persistence.minKeptInMemory=100\nspring.mail.scheduler.persistence.maxKeptInMemory=1000\n```\n\nThe first defines the maximum amount of emails being loaded from the persistence layer when a slot is available in the\npriority queues; the second amount is the wish for the minimum amount of emails available in memory: the third defines \nthe amount of emails to be kept in memory. Clearly, these two values impact the response time of the scheduler. \nThe less you store in memory, the more it takes to send the next email. The smaller\nis the batch size, the higher the times you interact with the persistence layer.\n\n## Customize email logging\nVery often, you want to log the email that you just sent or scheduled, but you would like to avoid a full \n`toString` of the given email object. For instance, you may want to anonymize an email address, or to ignore custom headers.\nHere follows a list of properties you can use with some examples:\n\n```properties\nspring.mail.logging.enabled=true\n\nspring.mail.logging.strategy.from=PLAIN_TEXT\nspring.mail.logging.strategy.replyTo=HIDDEN\nspring.mail.logging.strategy.to=FULL_TEXT_FROM_COMMERCIAL_AT,\nspring.mail.logging.strategy.cc=HIDDEN\nspring.mail.logging.strategy.bcc=HIDDEN\nspring.mail.logging.strategy.subject=PLAIN_TEXT\nspring.mail.logging.strategy.body=FIRST_DOZEN_THEN_STARS\nspring.mail.logging.strategy.attachments=HIDDEN\nspring.mail.logging.strategy.encoding=HIDDEN\nspring.mail.logging.strategy.locale=HIDDEN\nspring.mail.logging.strategy.sentAt=STANDARD_DATE_FORMAT_WITH_ZONE_ID\nspring.mail.logging.strategy.receiptTo=HIDDEN\nspring.mail.logging.strategy.depositionNotificationTo=HIDDEN\nspring.mail.logging.strategy.ignore.customHeaders=true\nspring.mail.logging.strategy.ignore.nullAndEmptyCollections=true\n```\n\nAllowed logging strategies are defined in the enum `it.ozimov.springboot.mail.logging.LoggingStrategy`.\nDo not pretend to apply a date-only strategy to an email address, or an email address-only strategy to \na text field. Usage should be straightforward.\n\n## Future plans\n\nSee open issues.\n\n**Any contribution is welcome (and warmly encouraged).**\n\n\n## License\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n## How to open an issue\n\nAre you experiencing an issue? Please, post a question on _StackOverflow_ or open an issue on GitHub.\n\nIssues that are not reporting a minimal set of info to reproduce the bug will be closed with no further comments.\n\nInformation that should be provided for investigations:\n- version used\n- pom.xml\n- application.properties\n- exception stacktrace\n- Are the provided examples run with success?\n\n\n==============================================\n\n[![forthebadge](http://forthebadge.com/images/badges/built-by-developers.svg)](http://forthebadge.com)\n[![forthebadge](http://forthebadge.com/images/badges/built-with-love.svg)](http://forthebadge.com)\n[![forthebadge](http://forthebadge.com/images/badges/pretty-risque.svg)](http://forthebadge.com)\n[![forthebadge](http://forthebadge.com/images/badges/makes-people-smile.svg)](http://forthebadge.com)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fozimov%2Fspring-boot-email-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fozimov%2Fspring-boot-email-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fozimov%2Fspring-boot-email-tools/lists"}