Skip to content

Commit

Permalink
Send SentMail Instances When Sending Emails
Browse files Browse the repository at this point in the history
This commit introduces the use of CDI events to emit instances of SentMail whenever an email is successfully sent.

The SentMail class is an immutable representation of the sent email, preventing unintended modifications. By leveraging CDI events, this approach avoids the need to introduce a new API.

Fixes quarkusio#45135.
  • Loading branch information
cescoffier committed Dec 17, 2024
1 parent 0396c33 commit 8d58795
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package io.quarkus.mailer;

import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.concurrent.CompletionStage;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;

Expand All @@ -28,7 +30,7 @@ public class InjectionTest {
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar
.addClasses(BeanUsingBareMailClient.class, BeanUsingBlockingMailer.class,
BeanUsingReactiveMailer.class, MailTemplates.class)
BeanUsingReactiveMailer.class, MailTemplates.class, MailListener.class)
.addAsResource("mock-config.properties", "application.properties")
.addAsResource(new StringAsset(""
+ "<html>{name}</html>"), "templates/test1.html")
Expand Down Expand Up @@ -56,15 +58,33 @@ public class InjectionTest {
@Inject
MailTemplates templates;

@Inject
MailListener listener;

@Test
public void testInjection() {
beanUsingMutiny.verify();
beanUsingBare.verify();
beanUsingBlockingMailer.verify();

await().until(() -> listener.getLast() != null);
listener.reset();

beanUsingReactiveMailer.verify().toCompletableFuture().join();
templates.send1();
templates.send2().await();
templates.sendNative().await();
await().until(() -> listener.getLast() != null);
listener.reset();

templates.send1().await().indefinitely();
await().until(() -> listener.getLast() != null);
listener.reset();

templates.send2().await().indefinitely();
await().until(() -> listener.getLast() != null);
listener.reset();

templates.sendNative().await().indefinitely();
await().until(() -> listener.getLast() != null);
listener.reset();
assertEquals("<html>Me</html>", MailTemplates.Templates.testNative("Me").templateInstance().render());
}

Expand Down Expand Up @@ -139,4 +159,22 @@ Uni<Void> sendNative() {
return Templates.testNative("John").to("quarkus@quarkus.io").subject("Test").send();
}
}

@ApplicationScoped
public static class MailListener {

volatile SentMail last;

public void onMailSent(@Observes SentMail mail) {
last = mail;
}

public SentMail getLast() {
return last;
}

public void reset() {
last = null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.quarkus.mailer;

import java.util.List;
import java.util.Map;

/**
* Represents a sent mail.
* Instances of this class are sent using CDI events.
*
* @param from the sender address
* @param to the list of recipients
* @param cc the list of CC recipients
* @param bcc the list of BCC recipients
* @param replyTo the list of reply-to addresses
* @param bounceAddress the bounce address
* @param subject the subject
* @param textBody the text body
* @param htmlBody the HTML body
* @param headers the headers
* @param attachments the attachments
*/
public record SentMail(String from,
List<String> to, List<String> cc, List<String> bcc,
String replyTo, String bounceAddress,
String subject, String textBody, String htmlBody,
Map<String, List<String>> headers, List<Attachment> attachments) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static java.util.Arrays.stream;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
Expand All @@ -13,10 +14,14 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import jakarta.enterprise.event.Event;

import org.jboss.logging.Logger;

import io.quarkus.arc.Arc;
import io.quarkus.mailer.Attachment;
import io.quarkus.mailer.Mail;
import io.quarkus.mailer.SentMail;
import io.quarkus.mailer.reactive.ReactiveMailer;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
Expand Down Expand Up @@ -51,6 +56,7 @@ public class MutinyMailerImpl implements ReactiveMailer {
private final boolean logRejectedRecipients;

private final boolean logInvalidRecipients;
private final Event<SentMail> sentEmailEvent;

MutinyMailerImpl(Vertx vertx, MailClient client, MockMailboxImpl mockMailbox,
String from, String bounceAddress, boolean mock, List<Pattern> approvedRecipients,
Expand All @@ -64,6 +70,11 @@ public class MutinyMailerImpl implements ReactiveMailer {
this.approvedRecipients = approvedRecipients;
this.logRejectedRecipients = logRejectedRecipients;
this.logInvalidRecipients = logInvalidRecipients;
if (Arc.container() != null) {
this.sentEmailEvent = Arc.container().beanManager().getEvent().select(SentMail.class);
} else {
this.sentEmailEvent = null;
}
}

@Override
Expand Down Expand Up @@ -128,13 +139,33 @@ private Uni<Void> send(Mail mail, MailMessage message) {
message.getCc(), message.getBcc(),
message.getText() == null ? "<empty>" : message.getText(),
message.getHtml() == null ? "<empty>" : message.getHtml());
return mockMailbox.send(mail, message);
return mockMailbox.send(mail, message)
.invoke(() -> fire(mail, message));
} else {
return client.sendMail(message)
.invoke(() -> fire(mail, message))
.replaceWithVoid();
}
}

private Map<String, List<String>> copy(MultiMap headers) {
return headers.entries().stream()
.collect(
Collectors.groupingBy(Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
}

private void fire(Mail mail, MailMessage message) {
if (sentEmailEvent != null) {
SentMail sentMail = new SentMail(message.getFrom(),
Collections.unmodifiableList(message.getTo()), Collections.unmodifiableList(message.getCc()),
Collections.unmodifiableList(message.getBcc()),
mail.getReplyTo(), message.getBounceAddress(),
message.getSubject(), message.getText(), message.getHtml(),
copy(message.getHeaders()), Collections.unmodifiableList(mail.getAttachments()));
sentEmailEvent.fire(sentMail);
}
}

private Uni<MailMessage> toMailMessage(Mail mail) {
MailMessage message = new MailMessage();

Expand Down

0 comments on commit 8d58795

Please sign in to comment.