Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow more than one Reply-To contact in order to be compliant with the Mail RFC #265

Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@ private SendEmailRequest sendEmailRequest(@NonNull Email email) {
.destination(destinationBuilder(email).build())
.source(email.getFrom().getEmail())
.message(message(email));
if (email.getReplyTo() != null) {
requestBuilder = requestBuilder.replyToAddresses(email.getReplyTo().getEmail());
if (CollectionUtils.isNotEmpty(email.getReplyToCollection())) {
requestBuilder = requestBuilder.replyToAddresses(
email.getReplyToCollection().stream().map(Contact::getEmail).toList());
}
return requestBuilder.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ class SesEmailComposerSpec extends Specification {

void "from, to and subject are put to the mime message"() {
given:
def from = "sender@example.com"
def to = "receiver@example.com"
def subject = "Apple Music"
String from = "sender@example.com"
String to = "receiver@example.com"
String subject = "Apple Music"

Email email = Email.builder()
.from(from)
Expand All @@ -26,7 +26,7 @@ class SesEmailComposerSpec extends Specification {
.body("Lore ipsum body")
.build()
when:
def request = sesEmailComposer.compose(email) as SendEmailRequest
SendEmailRequest request = sesEmailComposer.compose(email)

then:
from == request.source()
Expand All @@ -38,10 +38,10 @@ class SesEmailComposerSpec extends Specification {

void "from, to, cc and subject are put to the mime message"() {
given:
def from = "sender@example.com"
def to = "receiver@example.com"
def cc = "receiver.cc@example.com"
def subject = "Apple Music"
String from = "sender@example.com"
String to = "receiver@example.com"
String cc = "receiver.cc@example.com"
String subject = "Apple Music"

Email email = Email.builder()
.from(from)
Expand All @@ -51,7 +51,7 @@ class SesEmailComposerSpec extends Specification {
.body("Lore ipsum body")
.build()
when:
def request = sesEmailComposer.compose(email) as SendEmailRequest
SendEmailRequest request = sesEmailComposer.compose(email)

then:
from == request.source()
Expand All @@ -63,10 +63,10 @@ class SesEmailComposerSpec extends Specification {

void "from, to, bcc and subject are put to the mime message"() {
given:
def from = "sender@example.com"
def to = "receiver@example.com"
def bcc = "receiver.bcc@example.com"
def subject = "Apple Music"
String from = "sender@example.com"
String to = "receiver@example.com"
String bcc = "receiver.bcc@example.com"
String subject = "Apple Music"

Email email = Email.builder()
.from(from)
Expand All @@ -76,7 +76,7 @@ class SesEmailComposerSpec extends Specification {
.body("Lore ipsum body")
.build()
when:
def request = sesEmailComposer.compose(email) as SendEmailRequest
SendEmailRequest request = sesEmailComposer.compose(email)

then:
from == request.source()
Expand All @@ -88,10 +88,10 @@ class SesEmailComposerSpec extends Specification {

void "from, to, reply to and subject are put to the mime message"() {
given:
def from = "sender@example.com"
def to = "receiver@example.com"
def replyTo = "sender.reply.to@example.com"
def subject = "Apple Music"
String from = "sender@example.com"
String to = "receiver@example.com"
String replyTo = "sender.reply.to@example.com"
String subject = "Apple Music"

Email email = Email.builder()
.from(from)
Expand All @@ -101,7 +101,7 @@ class SesEmailComposerSpec extends Specification {
.body("Lore ipsum body")
.build()
when:
def request = sesEmailComposer.compose(email) as SendEmailRequest
SendEmailRequest request = sesEmailComposer.compose(email)

then:
from == request.source()
Expand All @@ -110,4 +110,31 @@ class SesEmailComposerSpec extends Specification {
subject == request.message().subject().data()
!request.destination().ccAddresses()
}

void "from, to, multiple reply to and subject are put to the mime message"() {
given:
String from = "sender@example.com"
String to = "receiver@example.com"
String replyTo1 = "sender.reply.to.one@example.com"
String replyTo2 = "sender.reply.to.two@example.com"
String subject = "Apple Music"

Email email = Email.builder()
.from(from)
.to(to)
.replyTo(replyTo1)
.replyTo(replyTo2)
.subject(subject)
.body("Lore ipsum body")
.build()
when:
SendEmailRequest request = sesEmailComposer.compose(email)

then:
from == request.source()
[to] == request.destination().toAddresses().toList()
[replyTo1, replyTo2] == request.replyToAddresses()
subject == request.message().subject().data()
!request.destination().ccAddresses()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

/**
* {@link io.micronaut.context.annotation.DefaultImplementation} of {@link MessageComposer}.
Expand Down Expand Up @@ -84,8 +83,8 @@ public Message compose(@NonNull Email email,
if (CollectionUtils.isNotEmpty(email.getBcc())) {
message.setRecipients(Message.RecipientType.BCC, contactAddresses(email.getBcc()));
}
if (null != email.getReplyTo()) {
message.setReplyTo(contactAddresses(Stream.of(email.getReplyTo()).toList()));
if (CollectionUtils.isNotEmpty(email.getReplyToCollection())) {
message.setReplyTo(contactAddresses(email.getReplyToCollection()));
}

MimeMultipart multipart = new MimeMultipart();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ class DefaultMessageComposerSpec extends Specification {

void "from, to and subject are put to the mime message"() {
given:
def from = "sender@example.com"
def to = "receiver@example.com"
def subject = "Apple Music"
String from = "sender@example.com"
String to = "receiver@example.com"
String subject = "Apple Music"

Email email = Email.builder()
.from(from)
Expand All @@ -25,7 +25,7 @@ class DefaultMessageComposerSpec extends Specification {
.body("Lore ipsum body")
.build()
when:
def message = defaultMessageComposer.compose(email, null)
Message message = defaultMessageComposer.compose(email, null)

then:
[from] == message.from.toList().collect {it.address }
Expand All @@ -37,10 +37,10 @@ class DefaultMessageComposerSpec extends Specification {

void "from, to, cc and subject are put to the mime message"() {
given:
def from = "sender@example.com"
def to = "receiver@example.com"
def cc = "receiver.cc@example.com"
def subject = "Apple Music"
String from = "sender@example.com"
String to = "receiver@example.com"
String cc = "receiver.cc@example.com"
String subject = "Apple Music"

Email email = Email.builder()
.from(from)
Expand All @@ -50,7 +50,7 @@ class DefaultMessageComposerSpec extends Specification {
.body("Lore ipsum body")
.build()
when:
def message = defaultMessageComposer.compose(email, null)
Message message = defaultMessageComposer.compose(email, null)

then:
[from] == message.from.toList().collect {it.address }
Expand All @@ -62,10 +62,10 @@ class DefaultMessageComposerSpec extends Specification {

void "from, to, bcc and subject are put to the mime message"() {
given:
def from = "sender@example.com"
def to = "receiver@example.com"
def bcc = "receiver.bcc@example.com"
def subject = "Apple Music"
String from = "sender@example.com"
String to = "receiver@example.com"
String bcc = "receiver.bcc@example.com"
String subject = "Apple Music"

Email email = Email.builder()
.from(from)
Expand All @@ -75,7 +75,7 @@ class DefaultMessageComposerSpec extends Specification {
.body("Lore ipsum body")
.build()
when:
def message = defaultMessageComposer.compose(email, null)
Message message = defaultMessageComposer.compose(email, null)

then:
[from] == message.from.toList().collect {it.address }
Expand All @@ -87,10 +87,10 @@ class DefaultMessageComposerSpec extends Specification {

void "from, to, reply to and subject are put to the mime message"() {
given:
def from = "sender@example.com"
def to = "receiver@example.com"
def replyTo = "sender.reply.to@example.com"
def subject = "Apple Music"
String from = "sender@example.com"
String to = "receiver@example.com"
String replyTo = "sender.reply.to@example.com"
String subject = "Apple Music"

Email email = Email.builder()
.from(from)
Expand All @@ -100,7 +100,7 @@ class DefaultMessageComposerSpec extends Specification {
.body("Lore ipsum body")
.build()
when:
def message = defaultMessageComposer.compose(email, null)
Message message = defaultMessageComposer.compose(email, null)

then:
[from] == message.from.toList().collect {it.address }
Expand All @@ -109,4 +109,31 @@ class DefaultMessageComposerSpec extends Specification {
subject == message.getSubject()
!message.getRecipients(Message.RecipientType.CC)
}

void "from, to, multiple reply to and subject are put to the mime message"() {
given:
String from = "sender@example.com"
String to = "receiver@example.com"
String replyTo1 = "sender.reply.to.one@example.com"
String replyTo2 = "sender.reply.to.two@example.com"
String subject = "Apple Music"

Email email = Email.builder()
.from(from)
.to(to)
.replyTo(replyTo1)
.replyTo(replyTo2)
.subject(subject)
.body("Lore ipsum body")
.build()
when:
Message message = defaultMessageComposer.compose(email, null)

then:
[from] == message.from.toList().collect {it.address }
[to] == message.getRecipients(Message.RecipientType.TO).toList().collect{it.address}
[replyTo1, replyTo2] == message.replyTo.toList().collect {it.address }
subject == message.getSubject()
!message.getRecipients(Message.RecipientType.CC)
}
}
1 change: 1 addition & 0 deletions email-mailjet/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ dependencies {
implementation(mnValidation.micronaut.validation)
testImplementation(projects.testSuiteUtils)
testImplementation(mn.micronaut.http)
testImplementation(mnSerde.micronaut.serde.jackson)
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import jakarta.inject.Singleton;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
Expand All @@ -42,11 +44,20 @@
*/
@Singleton
public class MailjetEmailComposer implements EmailComposer<MailjetRequest> {

private static final Logger LOG = LoggerFactory.getLogger(MailjetEmailComposer.class);

@Override
@NonNull
public MailjetRequest compose(@NonNull @NotNull @Valid Email email) throws EmailException {
JSONObject message = new JSONObject();
message.put(Emailv31.Message.FROM, createJsonObject(email.getFrom()));
if (CollectionUtils.isNotEmpty(email.getReplyToCollection())) {
if (email.getReplyToCollection().size() > 1 && LOG.isWarnEnabled()) {
LOG.warn("Mailjet does not support multiple 'replyTo' addresses (Email has {} replyTo addresses)", email.getReplyToCollection().size());
}
message.put(Emailv31.Message.REPLYTO, createJsonObject(CollectionUtils.last(email.getReplyToCollection())));
}
to(email).ifPresent(jsonArray -> message.put(Emailv31.Message.TO, jsonArray));
message.put(Emailv31.Message.SUBJECT, email.getSubject());
Body body = email.getBody();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.micronaut.email.mailjet

import com.mailjet.client.MailjetRequest
import io.micronaut.email.Email
import io.micronaut.json.JsonMapper
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import jakarta.inject.Inject
import spock.lang.Specification

@MicronautTest(startApplication = false)
class MailjetEmailComposerSpec extends Specification {

@Inject
MailjetEmailComposer mailjetEmailComposer

@Inject
JsonMapper jsonMapper

void "from, to, only the last reply to and subject are put to the request"() {
given:
String from = "sender@example.com"
String to = "receiver@example.com"
String replyTo1 = "sender.reply.to.one@example.com"
String replyTo2 = "sender.reply.to.two@example.com"
String subject = "Apple Music"
String body = "Lore ipsum body"

Email email = Email.builder()
.from(from)
.to(to)
.replyTo(replyTo1)
.replyTo(replyTo2)
.subject(subject)
.body(body)
.build()
when:
MailjetRequest request = mailjetEmailComposer.compose(email)
Map map = jsonMapper.readValue(request.body, Map)

then:
map["Messages"][0]["ReplyTo"]["Email"] == replyTo2
map["Messages"][0]["TextPart"] == body
map["Messages"][0]["From"]["Email"] == from
map["Messages"][0]["To"][0]["Email"] == to
map["Messages"][0]["Subject"] == subject
}
}