Quarkus - Sending emails

This guide demonstrates how your Quarkus application can send emails using an SMTP server.

Prerequisites

To complete this guide, you need:

  • less than 15 minutes

  • The SMTP hostname, port and credentials, and an email address

  • an IDE

  • JDK 1.8+ installed with JAVA_HOME configured appropriately

  • Apache Maven 3.5.3+

  • GraalVM installed if you want to run in native mode.

Architecture

In this guide, we are going to see how you can send emails from a Quarkus application.It covers simple emails, attachments, inlined attachments, the reactive and imperative APIs…​

Creating the Maven Project

Create a new project with the following command:

  1. mvn io.quarkus:quarkus-maven-plugin:1.0.0.CR1:create \
  2. -DprojectGroupId=org.acme \
  3. -DprojectArtifactId=sending-email-quickstart \
  4. -Dextensions="mailer"
  5. cd sending-email-quickstart

If you already have an existing project, add the mailer extension:

  1. ./mvnw quarkus:add-extensions -Dextensions="mailer"

Configuring the mailer

The Quarkus mailer is using SMTP. In the src/main/resources/application.properties file, you need to configure the host, port, username, password as well as the other configuration aspect.Note that the password can also be configured using system properties and environment variables.

Here is an example using sendgrid:

  1. quarkus.mailer.from=test@quarkus.io
  2. quarkus.mailer.host=smtp.sendgrid.net
  3. quarkus.mailer.port=465
  4. quarkus.mailer.ssl=true
  5. quarkus.mailer.username=....
  6. quarkus.mailer.password=....
For more information about the Mailer extension configuration please refer to the Configuration Reference.

Sending simple emails

In a JAX-RS resource, or in a bean, you can inject the mailer as follows:

  1. @Inject
  2. Mailer mailer;
  3. @Inject
  4. ReactiveMailer reactiveMailer;

There are 2 APIs:

  • io.quarkus.mailer.Mailer provides the imperative (blocking and synchronous) API;

  • io.quarkus.mailer.ReactiveMailer provides the reactive (non-blocking and asynchronous) API

The two APIs are equivalent feature-wise. Actually the Mailer implementation is built on top of the ReactiveMailer implementation.

To send a simple email, proceed as follows:

  1. // Imperative API:
  2. mailer.send(Mail.withText("to@acme.org", "A simple email from quarkus", "This is my body."));
  3. // Reactive API:
  4. CompletionStage<Void> stage = reactiveMailer.send(Mail.withText("to@acme.org", "A reactive email from quarkus", "This is my body."));

For example, you can use the Mailer in a JAX-RS endpoint as follows:

  1. @GET
  2. @Path("/simple")
  3. public Response sendASimpleEmail() {
  4. mailer.send(Mail.withText("to@acme.org", "A simple email from quarkus", "This is my body"));
  5. return Response.accepted().build();
  6. }
  7. @GET
  8. @Path("/async")
  9. public CompletionStage<Response> sendASimpleEmailAsync() {
  10. return reactiveMailer.send(
  11. Mail.withText("to@acme.org", "A reactive email from quarkus", "This is my body"))
  12. .thenApply(x -> Response.accepted().build());
  13. }

With such a JAX-RS resource, you can check that everything is working with:

  1. curl http://localhost:8080/simple
  2. curl http://localhost:8080/async

You can create new io.quarkus.mailer.Mail instances from the constructor or from the Mail.withText andMail.withHtml helper methods. The Mail instance lets you add recipients (to, cc, or bcc), set the subject,headers, sender (from) address…​

You can also send several Mail objects in one call:

  1. mailer.send(mail1, mail2, mail3);

Sending attachments

To send attachment, just use the addAttachment methods on the io.quarkus.mailer.Mail instance:

  1. @GET
  2. @Path("/attachment")
  3. public Response sendEmailWithAttachment() {
  4. mailer.send(Mail.withText("to@acme.org", "An email from quarkus with attachment",
  5. "This is my body")
  6. .addAttachment("my-file.txt",
  7. "content of my file".getBytes(), "text/plain"));
  8. return Response.accepted().build();
  9. }

Attachments can be created from raw bytes (as shown in the snippet) or files.

Sending HTML emails with inlined attachments

When sending HTML email, you can add inlined attachments.For example, you can send an image with your email, and this image will be displayed in the mail content. If you put the image file into resources folder, you should specify the full path to the file. "e.g." "META-INF/resources/quarkus-logo.png" otherwise quarkus will lookup in the root folder of the project

  1. @GET
  2. @Path("/html")
  3. public Response sendingHTML() {
  4. String body = "<strong>Hello!</strong>" + "\n" +
  5. "<p>Here is an image for you: <img src=\"cid:my-image@quarkus.io\"/></p>" +
  6. "<p>Regards</p>";
  7. mailer.send(Mail.withHtml("to@acme.org", "An email in HTML", body)
  8. .addInlineAttachment("quarkus-logo.png",
  9. new File("quarkus-logo.png"),
  10. "image/png", "<my-image@quarkus.io>"));
  11. return Response.accepted().build();
  12. }

Note the content-id format and reference.By spec, when you create the inline attachment, the content-id must be structured as follows: <id@domain>.If you don’t wrap your content-id between <>, it is automatically wrapped for you.When you want to reference your attachment, for instance in the src attribute, use cid:id@domain (without the < and >).

Testing email sending

Because it is very inconvenient to send emails during development and testing, you can set the quarkus.mailer.mock booleanconfiguration to true to not actually send emails but print them on stdout and collect them in a MockMailbox bean instead.This is the default if you are running Quarkus in DEV or TEST mode.

You can then write tests to verify that your emails were sent, for example, by a REST endpoint:

  1. @QuarkusTest
  2. class MailTest {
  3. private static final String TO = "foo@quarkus.io";
  4. @Inject
  5. MockMailbox mailbox;
  6. @BeforeEach
  7. void init() {
  8. mailbox.clear();
  9. }
  10. @Test
  11. void testTextMail() throws MessagingException, IOException {
  12. // call a REST endpoint that sends email
  13. given()
  14. .when()
  15. .get("/send-email")
  16. .then()
  17. .statusCode(202)
  18. .body(is("OK"));
  19. // verify that it was sent
  20. List<Mail> sent = mailbox.getMessagesSentTo(TO);
  21. assertThat(sent).hasSize(1);
  22. Mail actual = sent.get(0);
  23. assertThat(actual.getText()).contains("Wake up!");
  24. assertThat(actual.getSubject()).isEqualTo("Alarm!");
  25. assertThat(mailbox.getTotalMessagesSent()).isEqualTo(6);
  26. }
  27. }

Gmail specific configuration

If you want to use the Gmail SMTP server, first create a dedicated password in Google Account > Security > App passwords or go to https://myaccount.google.com/apppasswords.

When done, you can configure your Quarkus application by adding the following properties to your application.properties:

With TLS:

  1. quarkus.mailer.from=YOUREMAIL@gmail.com
  2. quarkus.mailer.host=smtp.gmail.com
  3. quarkus.mailer.port=587
  4. quarkus.mailer.start-tls=REQUIRED
  5. quarkus.mailer.username=YOUREMAIL@gmail.com
  6. quarkus.mailer.password=YOURGENERATEDAPPLICATIONPASSWORD

Or with SSL:

  1. quarkus.mailer.from=YOUREMAIL@gmail.com
  2. quarkus.mailer.host=smtp.gmail.com
  3. quarkus.mailer.port=465
  4. quarkus.mailer.ssl=true
  5. quarkus.mailer.username=YOUREMAIL@gmail.com
  6. quarkus.mailer.password=YOURGENERATEDAPPLICATIONPASSWORD

Using SSL with native executables

Note that if you enable SSL for the mailer and you want to build a native executable, you will need to enable the SSL support.Please refer to the native-and-ssl.html[Using SSL With Native Executables] guide for more information.

Using the underlying Vert.x Mail Client

The Quarkus Mailer is implemented on top of the Vert.x Mail Client, providing an asynchronous and non-blocking way to send emails.If you need fine control on how the mail is sent, for instance if you need to retrieve the message ids, you can inject the underlying client, and use it directly:

  1. @Inject MailClient client;

Three API flavors are exposed:

  • the Axle client (io.vertx.axle.ext.mail.MailClient), using CompletionStage and Reactive Streams Publisher

  • the RX Java 2 client (io.vertx.reactivex.ext.mail.MailClient)

  • the bare client (io.vertx.ext.mail.MailClient)

Check the Using Vert.x guide for further details about these different APIs and how to select the most suitable for you.

The retrieved MailClient is configured using the configuration key presented above.You can also create your own instance, and pass your own configuration.

Conclusion

This guide has shown how you can send emails from a Quarkus application.The mailer extension works in JVM and native mode.

Mailer Configuration Reference

Configuration property fixed at build time - ️ Configuration property overridable at runtime

Configuration propertyTypeDefault
quarkus.mailer.fromConfigure the default from attribute. It’s the sender email address.string
quarkus.mailer.mockEnables the mock mode, not sending emails. The content of the emails is printed on the console. Disabled by default on PROD, enabled by default on DEV and TEST modes.boolean
quarkus.mailer.bounce-addressConfigures the default bounce email address.string
quarkus.mailer.hostThe SMTP host name.stringlocalhost
quarkus.mailer.portThe SMTP port.int
quarkus.mailer.usernameThe username.string
quarkus.mailer.passwordThe password.string
quarkus.mailer.sslEnables or disables the SSL on connect. false by default.booleanfalse
quarkus.mailer.trust-allSet whether to trust all certificates on ssl connect the option is also applied to STARTTLS operation. false by default.booleanfalse
quarkus.mailer.max-pool-sizeConfigures the maximum allowed number of open connections to the mail server If not set the default is 10.int
quarkus.mailer.own-host-nameThe hostname to be used for HELO/EHLO and the Message-IDstring
quarkus.mailer.keep-aliveSet if connection pool is enabled, true by default. If the connection pooling is disabled, the max number of sockets is enforced nevertheless.booleantrue
quarkus.mailer.disable-esmtpDisable ESMTP. false by default. The RFC-1869 states that clients should always attempt EHLO as first command to determine if ESMTP is supported, if this returns an error code, HELO is tried to use the regular SMTP command.booleanfalse
quarkus.mailer.start-tlsSet the TLS security mode for the connection. Either DISABLED, OPTIONAL or REQUIRED.string
quarkus.mailer.loginSet the login mode for the connection. Either DISABLED, OPTIONAL or REQUIREDstring
quarkus.mailer.auth-methodsSet the allowed auth methods. If defined, only these methods will be used, if the server supports them.string
quarkus.mailer.key-storeSet the key store.string
quarkus.mailer.key-store-passwordSet the key store password.string