-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18540 from cescoffier/new-mailer-doc
Rewrote mailer getting start guide and reference documentation
- Loading branch information
Showing
3 changed files
with
478 additions
and
346 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,350 @@ | ||
//// | ||
This guide is maintained in the main Quarkus repository | ||
and pull requests should be submitted there: | ||
https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc | ||
//// | ||
= Quarkus Mailer Reference Guide | ||
|
||
include::./attributes.adoc[] | ||
|
||
This guide is the companion from the xref:mailer.adoc[Mailer Getting Started Guide]. | ||
It explains in more details the configuration and usage of the Quarkus Mailer. | ||
|
||
== Mailer extension | ||
|
||
To use the mailer, you need to add the `quarkus-mailer` extension. | ||
|
||
You can add the extension to your project using: | ||
|
||
[source, bash] | ||
---- | ||
> ./mvnw quarkus:add-extensions -Dextensions="mailer" | ||
---- | ||
|
||
Or just add the following dependency to your project: | ||
|
||
[source, xml] | ||
---- | ||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-mailer</artifactId> | ||
</dependency> | ||
---- | ||
|
||
|
||
== Accessing the mailer | ||
|
||
You can inject the mailer in your application using: | ||
|
||
[source, java] | ||
---- | ||
@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 | ||
==== | ||
`io.quarkus.mailer.ReactiveMailer` is deprecated in favor of `io.quarkus.mailer.reactive.ReactiveMailer`. | ||
==== | ||
|
||
To send a simple email, proceed as follows: | ||
|
||
[source, java] | ||
---- | ||
// Imperative API: | ||
mailer.send(Mail.withText("[email protected]", "A simple email from quarkus", "This is my body.")); | ||
// Reactive API: | ||
Uni<Void> stage = reactiveMailer.send(Mail.withText("[email protected]", "A reactive email from quarkus", "This is my body.")); | ||
---- | ||
|
||
For example, you can use the `Mailer` in an HTTP endpoint as follows: | ||
|
||
[source, java] | ||
---- | ||
@GET | ||
@Path("/imperative") | ||
public void sendASimpleEmail() { | ||
mailer.send(Mail.withText("[email protected]", "A simple email from quarkus", "This is my body")); | ||
} | ||
@GET | ||
@Path("/reactive") | ||
public Uni<Void> sendASimpleEmailAsync() { | ||
return reactiveMailer.send( | ||
Mail.withText("[email protected]", "A reactive email from quarkus", "This is my body")); | ||
} | ||
---- | ||
|
||
== Creating Mail objects | ||
|
||
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: | ||
|
||
[source, java] | ||
---- | ||
mailer.send(mail1, mail2, mail3); | ||
---- | ||
|
||
[[attachments]] | ||
== Sending attachments | ||
|
||
To send attachments, just use the `addAttachment` methods on the `io.quarkus.mailer.Mail` instance: | ||
|
||
[source,java] | ||
---- | ||
@GET | ||
@Path("/attachment") | ||
public void sendEmailWithAttachment() { | ||
mailer.send(Mail.withText("[email protected]", "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. | ||
|
||
[[html]] | ||
== Sending HTML emails with inlined attachments | ||
|
||
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. | ||
|
||
[source, java] | ||
---- | ||
@GET | ||
@Path("/html") | ||
public void sendingHTML() { | ||
String body = "<strong>Hello!</strong>" + "\n" + | ||
"<p>Here is an image for you: <img src=\"cid:[email protected]\"/></p>" + | ||
"<p>Regards</p>"; | ||
mailer.send(Mail.withHtml("[email protected]", "An email in HTML", body) | ||
.addInlineAttachment("quarkus-logo.png", | ||
new File("quarkus-logo.png"), | ||
"image/png", "<[email protected]>")); | ||
} | ||
---- | ||
|
||
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 `>`). | ||
|
||
[[templates]] | ||
== Message Body Based on Qute Templates | ||
|
||
It's possible to inject a mail template, where the message body is created automatically using link:qute[Qute templates]. | ||
|
||
[source, java] | ||
---- | ||
@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("[email protected]") // <3> | ||
.subject("Hello from Qute template") | ||
.send(); // <4> | ||
} | ||
} | ||
---- | ||
<1> 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` and `src/main/resources/templates/MailingResource/hello.txt` templates to create the message body. | ||
<2> Set the data used in the template. | ||
<3> Create a mail template instance and set the recipient. | ||
<4> `MailTemplate.send()` triggers the rendering and, once finished, sends the e-mail via a `Mailer` 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: | ||
|
||
[source, java] | ||
---- | ||
@Inject | ||
@Location("hello") | ||
MailTemplate hello; // <1> | ||
@GET | ||
@Path("/mail") | ||
public Uni<Void> send() { | ||
return hello.to("[email protected]") // <2> | ||
.subject("Hello from Qute template") | ||
.data("name", "John") // <3> | ||
.send() // <4> | ||
} | ||
---- | ||
<1> 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 the `src/main/resources/templates/hello.html` and `src/main/resources/templates/hello.txt` templates to create the message body. | ||
<2> Create a mail template instance and set the recipient. | ||
<3> Set the data used in the template. | ||
<4> `MailTemplate.send()` triggers the rendering and, once finished, sends the e-mail via a `Mailer` instance. | ||
|
||
|
||
[[testing]] | ||
== Testing email sending | ||
|
||
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: | ||
|
||
[source, java] | ||
---- | ||
@QuarkusTest | ||
class MailTest { | ||
private static final String TO = "[email protected]"; | ||
@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); | ||
} | ||
} | ||
---- | ||
|
||
== Using the underlying Vert.x Mail Client | ||
|
||
The Quarkus Mailer is implemented on top of the https://vertx.io/docs/vertx-mail-client/java/[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: | ||
|
||
[source, java] | ||
---- | ||
@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 link:vertx[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. | ||
|
||
[#gmail-specific-configuration] | ||
== 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: | ||
|
||
[source,properties] | ||
---- | ||
quarkus.mailer.auth-methods=DIGEST-MD5 CRAM-SHA256 CRAM-SHA1 CRAM-MD5 PLAIN LOGIN | ||
[email protected] | ||
quarkus.mailer.host=smtp.gmail.com | ||
quarkus.mailer.port=587 | ||
quarkus.mailer.start-tls=REQUIRED | ||
[email protected] | ||
quarkus.mailer.password=YOURGENERATEDAPPLICATIONPASSWORD | ||
---- | ||
|
||
Or with SSL: | ||
|
||
[source,properties] | ||
---- | ||
quarkus.mailer.auth-methods=DIGEST-MD5 CRAM-SHA256 CRAM-SHA1 CRAM-MD5 PLAIN LOGIN | ||
[email protected] | ||
quarkus.mailer.host=smtp.gmail.com | ||
quarkus.mailer.port=465 | ||
quarkus.mailer.ssl=true | ||
[email protected] | ||
quarkus.mailer.password=YOURGENERATEDAPPLICATIONPASSWORD | ||
---- | ||
|
||
[NOTE] | ||
==== | ||
The `quarkus.mailer.auth-methods` configuration option is needed for the Quarkus mailer to support password authentication with Gmail. | ||
By default both the mailer and Gmail default to `XOAUTH2` which requires registering an application, getting tokens, etc. | ||
==== | ||
|
||
== 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 link:native-and-ssl[Using SSL With Native Executables] guide for more information. | ||
|
||
== Configuring the SMTP credentials | ||
|
||
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: | ||
|
||
[source,properties] | ||
---- | ||
... | ||
# 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, Configuration Reference>>. | ||
|
||
|
||
[[configuration-reference]] | ||
== Mailer Configuration Reference | ||
|
||
include::{generated-dir}/config/quarkus-mailer.adoc[opts=optional, leveloffset=+1] | ||
|
||
|
Oops, something went wrong.