This guide is the companion from the Mailer Getting Started Guide. It explains in more details the configuration and usage of the Quarkus Mailer.
To use the mailer, you need to add the quarkus-mailer
extension.
You can add the extension to your project using:
> ./mvnw quarkus:add-extensions -Dextensions="mailer"
Or just add the following dependency to your project:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-mailer</artifactId>
</dependency>
You can inject the mailer in your application using:
@Inject
Mailer mailer;
@Inject
ReactiveMailer reactiveMailer;
There are 2 APIs:
-
io.quarkus.mailer.Mailer
provides the imperative (blocking and synchronous) API; -
io.quarkus.mailer.reactive.ReactiveMailer
provides the reactive (non-blocking and asynchronous) API
Note
|
The two APIs are equivalent feature-wise. Actually the Mailer implementation is built on top of the ReactiveMailer implementation.
|
Note
|
Deprecation
|
To send a simple email, proceed as follows:
// Imperative API:
mailer.send(Mail.withText("to@acme.org", "A simple email from quarkus", "This is my body."));
// Reactive API:
Uni<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 an HTTP endpoint as follows:
@GET
@Path("/imperative")
public void sendASimpleEmail() {
mailer.send(Mail.withText("to@acme.org", "A simple email from quarkus", "This is my body"));
}
@GET
@Path("/reactive")
public Uni<Void> sendASimpleEmailAsync() {
return reactiveMailer.send(
Mail.withText("to@acme.org", "A reactive email from quarkus", "This is my body"));
}
The mailer lets you send io.quarkus.mailer.Mail
objects.
You can create new io.quarkus.mailer.Mail
instances from the constructor or from the Mail.withText
and
Mail.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:
mailer.send(mail1, mail2, mail3);
To send attachments, just use the addAttachment
methods on the io.quarkus.mailer.Mail
instance:
@GET
@Path("/attachment")
public void sendEmailWithAttachment() {
mailer.send(Mail.withText("clement.escoffier@gmail.com", "An email from quarkus with attachment",
"This is my body")
.addAttachment("my-file-1.txt",
"content of my file".getBytes(), "text/plain")
.addAttachment("my-file-2.txt",
new File("my-file.txt"), "text/plain")
);
}
Attachments can be created from raw bytes (as shown in the snippet) or files. Note that files are resolved from the working directory of the application.
When sending HTML emails, 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 the META-INF/resources
folder, you should specify the full path to the file, e.g. META-INF/resources/quarkus-logo.png
otherwise Quarkus will look for the file in the root directory.
@GET
@Path("/html")
public void sendingHTML() {
String body = "<strong>Hello!</strong>" + "\n" +
"<p>Here is an image for you: <img src=\"cid:my-image@quarkus.io\"/></p>" +
"<p>Regards</p>";
mailer.send(Mail.withHtml("to@acme.org", "An email in HTML", body)
.addInlineAttachment("quarkus-logo.png",
new File("quarkus-logo.png"),
"image/png", "<my-image@quarkus.io>"));
}
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 >
).
It’s possible to inject a mail template, where the message body is created automatically using Qute templates.
@Path("")
public class MailingResource {
@CheckedTemplate
static class Templates {
public static native MailTemplateInstance hello(String name); // (1)
}
@GET
@Path("/mail")
public Uni<Void> send() {
// the template looks like: Hello {name}! // (2)
return Templates.hello("John")
.to("to@acme.org") // (3)
.subject("Hello from Qute template")
.send(); // (4)
}
}
-
By convention, the enclosing class name and method names are used to locate the template. In this particular case, we will use the
src/main/resources/templates/MailingResource/hello.html
andsrc/main/resources/templates/MailingResource/hello.txt
templates to create the message body. -
Set the data used in the template.
-
Create a mail template instance and set the recipient.
-
MailTemplate.send()
triggers the rendering and, once finished, sends the e-mail via aMailer
instance.
Tip
|
Injected mail templates are validated during build.
The build fails if there is no matching template in src/main/resources/templates .
|
You can also do this without type-safe templates:
@Inject
@Location("hello")
MailTemplate hello; // (1)
@GET
@Path("/mail")
public Uni<Void> send() {
return hello.to("to@acme.org") // (2)
.subject("Hello from Qute template")
.data("name", "John") // (3)
.send() // (4)
}
-
If there is no
@Location
qualifier provided, the field name is used to locate the template. Otherwise, search for the template as the specified location. In this particular case, we will use thesrc/main/resources/templates/hello.html
andsrc/main/resources/templates/hello.txt
templates to create the message body. -
Create a mail template instance and set the recipient.
-
Set the data used in the template.
-
MailTemplate.send()
triggers the rendering and, once finished, sends the e-mail via aMailer
instance.
The reactive mailer is non-blocking, and the results are provided on an I/O thread. See the Quarkus Reactive Architecture documentation for further details on this topic.
The non-reactive mailer blocks until the messages are sent to the SMTP server. Note that does not mean that the message is delivered, just that it’s been sent successfully to the SMTP server, which will be responsible for the delivery.
Because it is very inconvenient to send emails during development and testing, you can set the quarkus.mailer.mock
boolean
configuration to true
to prevent the actual sending of emails but instead 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:
@QuarkusTest
class MailTest {
private static final String TO = "foo@quarkus.io";
@Inject
MockMailbox mailbox;
@BeforeEach
void init() {
mailbox.clear();
}
@Test
void testTextMail() throws MessagingException, IOException {
// call a REST endpoint that sends email
given()
.when()
.get("/send-email")
.then()
.statusCode(202)
.body(is("OK"));
// verify that it was sent
List<Mail> sent = mailbox.getMessagesSentTo(TO);
assertThat(sent).hasSize(1);
Mail actual = sent.get(0);
assertThat(actual.getText()).contains("Wake up!");
assertThat(actual.getSubject()).isEqualTo("Alarm!");
assertThat(mailbox.getTotalMessagesSent()).isEqualTo(6);
}
}
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:
@Inject MailClient client;
Three API flavors are exposed:
-
the Mutiny client (
io.vertx.mutiny.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.
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.
Note
|
You need to switch on 2-Step Verification at https://myaccount.google.com/security in order to access the App passwords page. |
When done, you can configure your Quarkus application by adding the following properties to your application.properties
:
With TLS:
quarkus.mailer.auth-methods=DIGEST-MD5 CRAM-SHA256 CRAM-SHA1 CRAM-MD5 PLAIN LOGIN
quarkus.mailer.from=YOUREMAIL@gmail.com
quarkus.mailer.host=smtp.gmail.com
quarkus.mailer.port=587
quarkus.mailer.start-tls=REQUIRED
quarkus.mailer.username=YOUREMAIL@gmail.com
quarkus.mailer.password=YOURGENERATEDAPPLICATIONPASSWORD
Or with SSL:
quarkus.mailer.auth-methods=DIGEST-MD5 CRAM-SHA256 CRAM-SHA1 CRAM-MD5 PLAIN LOGIN
quarkus.mailer.from=YOUREMAIL@gmail.com
quarkus.mailer.host=smtp.gmail.com
quarkus.mailer.port=465
quarkus.mailer.ssl=true
quarkus.mailer.username=YOUREMAIL@gmail.com
quarkus.mailer.password=YOURGENERATEDAPPLICATIONPASSWORD
Note
|
The |
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 Using SSL With Native Executables guide for more information.
It is recommended to encrypt any sensitive data, such as the quarkus.mailer.password
.
One approach is to save the value into a secure store like HashiCorp Vault, and refer to it from the configuration.
Assuming for instance that Vault contains key mail-password
at path myapps/myapp/myconfig
, then the mailer
extension can be simply configured as:
...
# path within the kv secret engine where is located the application sensitive configuration
quarkus.vault.secret-config-kv-path=myapps/myapp/myconfig
...
quarkus.mailer.password=${mail-password}
Please note that the password value is evaluated only once, at startup time. If mail-password
was changed in Vault,
the only way to get the new value would be to restart the application.
Tip
|
For more information about the Mailer configuration please refer to the Configuration Reference. |
If your SMTP requires a trust store, you can configure the trust store as follows:
quarkus.mailer.host=...
quarkus.mailer.port=...
quarkus.mailer.ssl=true
quarkus.mailer.trust-store.paths=truststore.jks # the path to your trust store
quarkus.mailer.trust-store.password=secret # the trust store password if any
quarkus.mailer.trust-store.type=JKS # the type of trust store if it can't be deduced from the file extension
Quarkus mailer supports JKS, PKCS#12 and PEM trust stores. For PEM, you can configure multiple files. For JKS and PKCS#12, you can configure the password if any.
quarkus.mailer.trust-store.type
is optional and allows configuring the type of trust store (among JKS
, PEM
and PKCS
).
When not set, Quarkus tries to deduce the type from the file name.
Note
|
You can also configure quarkus.mailer.trust-all=true to bypass the verification.
|