From 25d33e77e1dbac4d7802859d75f7cb24d6a5c9a4 Mon Sep 17 00:00:00 2001 From: vtasun Date: Wed, 10 Sep 2025 01:36:43 +0300 Subject: [PATCH 1/5] Implement `/batch` method for sending/testing/bulk emails --- .../java/io/mailtrap/examples/bulk/Batch.java | 43 ++++++++++ .../io/mailtrap/examples/sending/Batch.java | 43 ++++++++++ .../io/mailtrap/examples/testing/Batch.java | 48 +++++++++++ .../api/apiresource/SendApiResource.java | 13 ++- .../mailtrap/api/bulkemails/BulkEmails.java | 4 + .../api/bulkemails/BulkEmailsImpl.java | 19 ++++- .../api/sendingemails/SendingEmails.java | 4 + .../api/sendingemails/SendingEmailsImpl.java | 18 +++- .../api/testingemails/TestingEmails.java | 4 + .../api/testingemails/TestingEmailsImpl.java | 19 ++++- .../io/mailtrap/client/MailtrapClient.java | 18 ++++ .../model/request/emails/BatchEmailBase.java | 67 +++++++++++++++ .../request/emails/MailtrapBatchMail.java | 19 +++++ .../response/emails/BatchSendDetails.java | 17 ++++ .../response/emails/BatchSendResponse.java | 16 ++++ .../api/bulkemails/BulkEmailsImplTest.java | 77 ++++++++++++++--- .../sendingemails/SendingEmailsImplTest.java | 75 ++++++++++++++--- .../testingemails/TestingEmailsImplTest.java | 54 ++++++++++++ .../mailtrap/client/MailtrapClientTest.java | 84 +++++++++++++++---- .../io/mailtrap/testutils/BaseSendTest.java | 1 + .../api/emails/batchSendRequest.json | 26 ++++++ .../emails/batchSendRequestFromTemplate.json | 25 ++++++ .../api/emails/batchSendResponse.json | 13 +++ 23 files changed, 663 insertions(+), 44 deletions(-) create mode 100644 examples/java/io/mailtrap/examples/bulk/Batch.java create mode 100644 examples/java/io/mailtrap/examples/sending/Batch.java create mode 100644 examples/java/io/mailtrap/examples/testing/Batch.java create mode 100644 src/main/java/io/mailtrap/model/request/emails/BatchEmailBase.java create mode 100644 src/main/java/io/mailtrap/model/request/emails/MailtrapBatchMail.java create mode 100644 src/main/java/io/mailtrap/model/response/emails/BatchSendDetails.java create mode 100644 src/main/java/io/mailtrap/model/response/emails/BatchSendResponse.java create mode 100644 src/test/resources/api/emails/batchSendRequest.json create mode 100644 src/test/resources/api/emails/batchSendRequestFromTemplate.json create mode 100644 src/test/resources/api/emails/batchSendResponse.json diff --git a/examples/java/io/mailtrap/examples/bulk/Batch.java b/examples/java/io/mailtrap/examples/bulk/Batch.java new file mode 100644 index 0000000..2348731 --- /dev/null +++ b/examples/java/io/mailtrap/examples/bulk/Batch.java @@ -0,0 +1,43 @@ +package io.mailtrap.examples.bulk; + +import io.mailtrap.config.MailtrapConfig; +import io.mailtrap.factory.MailtrapClientFactory; +import io.mailtrap.model.request.emails.Address; +import io.mailtrap.model.request.emails.MailtrapBatchMail; +import io.mailtrap.model.request.emails.BatchEmailBase; +import io.mailtrap.model.request.emails.MailtrapMail; + +import java.util.List; +import java.util.Map; + +public class Bulk { + + private static final String TOKEN = ""; + private static final String SENDER_EMAIL = "sender@domain.com"; + private static final String RECIPIENT_EMAIL = "recipient@domain.com"; + + public static void main(String[] args) { + final var config = new MailtrapConfig.Builder() + .token(TOKEN) + .build(); + + final var client = MailtrapClientFactory.createMailtrapClient(config); + + final var mail = MailtrapMail.builder() + .from(new Address(SENDER_EMAIL)) + .to(List.of(new Address(RECIPIENT_EMAIL))) + .subject("Hello from Mailtrap!") + .text("Welcome to Mailtrap Bulk Sending!") + .build(); + + final var batchMail = MailtrapBatchMail.builder() + // Optionally you can add this `base` object - if you have some common data across emails + // Each property can be overridden in `requests` for individual emails + .base(BatchEmailBase.builder().subject("Base Subject for all emails").build()) + .requests(List.of(mail)) + .build(); + + System.out.println(client.bulkSendingApi().emails().batchSend(batchMail)); + } + +} diff --git a/examples/java/io/mailtrap/examples/sending/Batch.java b/examples/java/io/mailtrap/examples/sending/Batch.java new file mode 100644 index 0000000..e3799ec --- /dev/null +++ b/examples/java/io/mailtrap/examples/sending/Batch.java @@ -0,0 +1,43 @@ +package io.mailtrap.examples.sending; + +import io.mailtrap.config.MailtrapConfig; +import io.mailtrap.factory.MailtrapClientFactory; +import io.mailtrap.model.request.emails.Address; +import io.mailtrap.model.request.emails.MailtrapBatchMail; +import io.mailtrap.model.request.emails.BatchEmailBase; +import io.mailtrap.model.request.emails.MailtrapMail; + +import java.util.List; +import java.util.Map; + +public class Bulk { + + private static final String TOKEN = ""; + private static final String SENDER_EMAIL = "sender@domain.com"; + private static final String RECIPIENT_EMAIL = "recipient@domain.com"; + + public static void main(String[] args) { + final var config = new MailtrapConfig.Builder() + .token(TOKEN) + .build(); + + final var client = MailtrapClientFactory.createMailtrapClient(config); + + final var mail = MailtrapMail.builder() + .from(new Address(SENDER_EMAIL)) + .to(List.of(new Address(RECIPIENT_EMAIL))) + .subject("Hello from Mailtrap Sending!") + .text("Welcome to Mailtrap Sending!") + .build(); + + final var batchMail = MailtrapBatchMail.builder() + // Optionally you can add this `base` object - if you have some common data across emails + // Each property can be overridden in `requests` for individual emails + .base(BatchEmailBase.builder().subject("Base Subject for all emails").build()) + .requests(List.of(mail)) + .build(); + + System.out.println(client.sendingApi().emails().batchSend(batchMail)); + } + +} diff --git a/examples/java/io/mailtrap/examples/testing/Batch.java b/examples/java/io/mailtrap/examples/testing/Batch.java new file mode 100644 index 0000000..d6e017e --- /dev/null +++ b/examples/java/io/mailtrap/examples/testing/Batch.java @@ -0,0 +1,48 @@ +package io.mailtrap.examples.testing; + +import io.mailtrap.config.MailtrapConfig; +import io.mailtrap.factory.MailtrapClientFactory; +import io.mailtrap.model.request.emails.Address; +import io.mailtrap.model.request.emails.MailtrapBatchMail; +import io.mailtrap.model.request.emails.BatchEmailBase; +import io.mailtrap.model.request.emails.MailtrapMail; + +import java.util.List; +import java.util.Map; + +public class Batch { + + private static final String TOKEN = ""; + private static final String SENDER_EMAIL = "sender@domain.com"; + private static final String RECIPIENT_EMAIL = "recipient@domain.com"; + private static final long INBOX_ID = 1337L; + + public static void main(String[] args) { + final var config = new MailtrapConfig.Builder() + .token(TOKEN) + .inboxId(INBOX_ID) + .build(); + + final var client = MailtrapClientFactory.createMailtrapClient(config); + + final var mail = MailtrapMail.builder() + .from(new Address("John Doe", SENDER_EMAIL)) + .to(List.of(new Address("Jane Doe", RECIPIENT_EMAIL))) + .templateUuid("813t39es-t74i-4308-b037-0n6bg8b1fe88") + .templateVariables(Map.of( + "user_name", "Jack Sparrow", + "testing_template", "true" + )) + .build(); + + final var batchMail = MailtrapBatchMail.builder() + // Optionally you can add this `base` object - if you have some common data across emails + // Each property can be overridden in `requests` for individual emails + .base(BatchEmailBase.builder().subject("Base Subject for all emails").build()) + .requests(List.of(mail)) + .build(); + + System.out.println(client.testingApi().emails().batchSend(batchMail, config.getInboxId())); + } + +} diff --git a/src/main/java/io/mailtrap/api/apiresource/SendApiResource.java b/src/main/java/io/mailtrap/api/apiresource/SendApiResource.java index 72a35c4..795c453 100644 --- a/src/main/java/io/mailtrap/api/apiresource/SendApiResource.java +++ b/src/main/java/io/mailtrap/api/apiresource/SendApiResource.java @@ -3,6 +3,7 @@ import io.mailtrap.CustomValidator; import io.mailtrap.config.MailtrapConfig; import io.mailtrap.exception.InvalidRequestBodyException; +import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; @@ -16,13 +17,19 @@ protected SendApiResource(MailtrapConfig config, CustomValidator customValidator super(config, customValidator); } + protected void assertBatchMailNotNull(MailtrapBatchMail batchMail){ + if (batchMail == null) { + throw new InvalidRequestBodyException("BatchMail must not be null"); + } + } + /** * Validates the request body of an email message and throws an exception if it is invalid. * * @param mail The email message to be validated. * @throws InvalidRequestBodyException If the request body is invalid. */ - protected void validateRequestBodyOrThrowException(MailtrapMail mail) throws InvalidRequestBodyException { + protected void validateMailPayload(MailtrapMail mail) throws InvalidRequestBodyException { // Check if the mail object itself is null if (mail == null) { throw new InvalidRequestBodyException("Mail must not be null"); @@ -30,8 +37,8 @@ protected void validateRequestBodyOrThrowException(MailtrapMail mail) throws Inv // Check if all three subject, text, and html are empty boolean isSubjectTextHtmlEmpty = StringUtils.isEmpty(mail.getSubject()) - && StringUtils.isEmpty(mail.getText()) - && StringUtils.isEmpty(mail.getHtml()); + && StringUtils.isEmpty(mail.getText()) + && StringUtils.isEmpty(mail.getHtml()); // Validate depending on whether the templateUuid is set if (StringUtils.isEmpty(mail.getTemplateUuid())) { diff --git a/src/main/java/io/mailtrap/api/bulkemails/BulkEmails.java b/src/main/java/io/mailtrap/api/bulkemails/BulkEmails.java index ab6a8d8..e75b82d 100644 --- a/src/main/java/io/mailtrap/api/bulkemails/BulkEmails.java +++ b/src/main/java/io/mailtrap/api/bulkemails/BulkEmails.java @@ -2,7 +2,9 @@ import io.mailtrap.exception.InvalidRequestBodyException; import io.mailtrap.exception.http.HttpException; +import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; +import io.mailtrap.model.response.emails.BatchSendResponse; import io.mailtrap.model.response.emails.SendResponse; /** @@ -20,4 +22,6 @@ public interface BulkEmails { * @throws InvalidRequestBodyException If the request body is invalid. */ SendResponse send(MailtrapMail mail) throws HttpException, InvalidRequestBodyException; + + BatchSendResponse batchSend(MailtrapBatchMail mail) throws HttpException, InvalidRequestBodyException; } diff --git a/src/main/java/io/mailtrap/api/bulkemails/BulkEmailsImpl.java b/src/main/java/io/mailtrap/api/bulkemails/BulkEmailsImpl.java index c05e183..3973037 100644 --- a/src/main/java/io/mailtrap/api/bulkemails/BulkEmailsImpl.java +++ b/src/main/java/io/mailtrap/api/bulkemails/BulkEmailsImpl.java @@ -4,8 +4,12 @@ import io.mailtrap.CustomValidator; import io.mailtrap.api.apiresource.SendApiResource; import io.mailtrap.config.MailtrapConfig; +import io.mailtrap.exception.InvalidRequestBodyException; +import io.mailtrap.exception.http.HttpException; import io.mailtrap.http.RequestData; +import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; +import io.mailtrap.model.response.emails.BatchSendResponse; import io.mailtrap.model.response.emails.SendResponse; /** @@ -20,11 +24,24 @@ public BulkEmailsImpl(MailtrapConfig config, CustomValidator customValidator) { @Override public SendResponse send(MailtrapMail mail) { - validateRequestBodyOrThrowException(mail); + validateMailPayload(mail); RequestData requestData = new RequestData(); if (mail.getHeaders() != null) { requestData.setHeaders(mail.getHeaders()); } return httpClient.post(apiHost + "/api/send", mail, requestData, SendResponse.class); } + + @Override + public BatchSendResponse batchSend(MailtrapBatchMail mail) throws HttpException, InvalidRequestBodyException { + assertBatchMailNotNull(mail); + + mail + .getRequests() + .forEach(this::validateMailPayload); + + return + httpClient.post(apiHost + "/api/batch", mail, new RequestData(), BatchSendResponse.class); + + } } diff --git a/src/main/java/io/mailtrap/api/sendingemails/SendingEmails.java b/src/main/java/io/mailtrap/api/sendingemails/SendingEmails.java index b09fbd4..3a4ff9e 100644 --- a/src/main/java/io/mailtrap/api/sendingemails/SendingEmails.java +++ b/src/main/java/io/mailtrap/api/sendingemails/SendingEmails.java @@ -2,7 +2,9 @@ import io.mailtrap.exception.InvalidRequestBodyException; import io.mailtrap.exception.http.HttpException; +import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; +import io.mailtrap.model.response.emails.BatchSendResponse; import io.mailtrap.model.response.emails.SendResponse; /** @@ -20,4 +22,6 @@ public interface SendingEmails { * @throws InvalidRequestBodyException If the request body is invalid. */ SendResponse send(MailtrapMail mail) throws HttpException, InvalidRequestBodyException; + + BatchSendResponse batchSend(MailtrapBatchMail mail) throws HttpException, InvalidRequestBodyException; } diff --git a/src/main/java/io/mailtrap/api/sendingemails/SendingEmailsImpl.java b/src/main/java/io/mailtrap/api/sendingemails/SendingEmailsImpl.java index 2cf24bf..5b674e8 100644 --- a/src/main/java/io/mailtrap/api/sendingemails/SendingEmailsImpl.java +++ b/src/main/java/io/mailtrap/api/sendingemails/SendingEmailsImpl.java @@ -4,8 +4,12 @@ import io.mailtrap.CustomValidator; import io.mailtrap.api.apiresource.SendApiResource; import io.mailtrap.config.MailtrapConfig; +import io.mailtrap.exception.InvalidRequestBodyException; +import io.mailtrap.exception.http.HttpException; import io.mailtrap.http.RequestData; +import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; +import io.mailtrap.model.response.emails.BatchSendResponse; import io.mailtrap.model.response.emails.SendResponse; /** @@ -20,7 +24,7 @@ public SendingEmailsImpl(MailtrapConfig config, CustomValidator customValidator) @Override public SendResponse send(MailtrapMail mail) { - validateRequestBodyOrThrowException(mail); + validateMailPayload(mail); RequestData requestData = new RequestData(); if (mail.getHeaders() != null) { requestData.setHeaders(mail.getHeaders()); @@ -28,4 +32,16 @@ public SendResponse send(MailtrapMail mail) { return httpClient.post(apiHost + "/api/send", mail, requestData, SendResponse.class); } + @Override + public BatchSendResponse batchSend(MailtrapBatchMail mail) throws HttpException, InvalidRequestBodyException { + assertBatchMailNotNull(mail); + + mail + .getRequests() + .forEach(this::validateMailPayload); + + return + httpClient.post(apiHost + "/api/batch", mail, new RequestData(), BatchSendResponse.class); + } + } diff --git a/src/main/java/io/mailtrap/api/testingemails/TestingEmails.java b/src/main/java/io/mailtrap/api/testingemails/TestingEmails.java index 1c9f04f..63d207a 100644 --- a/src/main/java/io/mailtrap/api/testingemails/TestingEmails.java +++ b/src/main/java/io/mailtrap/api/testingemails/TestingEmails.java @@ -2,7 +2,9 @@ import io.mailtrap.exception.InvalidRequestBodyException; import io.mailtrap.exception.http.HttpException; +import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; +import io.mailtrap.model.response.emails.BatchSendResponse; import io.mailtrap.model.response.emails.SendResponse; /** @@ -21,4 +23,6 @@ public interface TestingEmails { * @throws InvalidRequestBodyException If the request body is invalid. */ SendResponse send(MailtrapMail mail, long inboxId) throws HttpException, InvalidRequestBodyException; + + BatchSendResponse batchSend(MailtrapBatchMail mail, long inboxId) throws HttpException, InvalidRequestBodyException; } diff --git a/src/main/java/io/mailtrap/api/testingemails/TestingEmailsImpl.java b/src/main/java/io/mailtrap/api/testingemails/TestingEmailsImpl.java index b948f4b..b95fb4f 100644 --- a/src/main/java/io/mailtrap/api/testingemails/TestingEmailsImpl.java +++ b/src/main/java/io/mailtrap/api/testingemails/TestingEmailsImpl.java @@ -4,8 +4,12 @@ import io.mailtrap.CustomValidator; import io.mailtrap.api.apiresource.SendApiResource; import io.mailtrap.config.MailtrapConfig; +import io.mailtrap.exception.InvalidRequestBodyException; +import io.mailtrap.exception.http.HttpException; import io.mailtrap.http.RequestData; +import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; +import io.mailtrap.model.response.emails.BatchSendResponse; import io.mailtrap.model.response.emails.SendResponse; /** @@ -20,11 +24,24 @@ public TestingEmailsImpl(MailtrapConfig config, CustomValidator customValidator) @Override public SendResponse send(MailtrapMail mail, long inboxId) { - validateRequestBodyOrThrowException(mail); + validateMailPayload(mail); RequestData requestData = new RequestData(); if (mail.getHeaders() != null) { requestData.setHeaders(mail.getHeaders()); } return httpClient.post(String.format(apiHost + "/api/send/%d", inboxId), mail, requestData, SendResponse.class); } + + @Override + public BatchSendResponse batchSend(MailtrapBatchMail mail, long inboxId) throws HttpException, InvalidRequestBodyException { + assertBatchMailNotNull(mail); + + mail + .getRequests() + .forEach(this::validateMailPayload); + + return + httpClient.post(String.format(apiHost + "/api/batch/%d", inboxId), mail, new RequestData(), BatchSendResponse.class); + + } } diff --git a/src/main/java/io/mailtrap/client/MailtrapClient.java b/src/main/java/io/mailtrap/client/MailtrapClient.java index 1a0b8fb..1776827 100644 --- a/src/main/java/io/mailtrap/client/MailtrapClient.java +++ b/src/main/java/io/mailtrap/client/MailtrapClient.java @@ -2,7 +2,9 @@ import io.mailtrap.client.api.*; import io.mailtrap.config.MailtrapConfig; +import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; +import io.mailtrap.model.response.emails.BatchSendResponse; import io.mailtrap.model.response.emails.SendResponse; import io.mailtrap.util.SendingContextHolder; import lombok.Getter; @@ -76,6 +78,22 @@ public SendResponse send(MailtrapMail mailtrapMail) { } } + /** + * Sends an email based on the specified sending configuration. + * + * @param mailtrapBatchMail emails to send + * @return the response from the sending operation + */ + public BatchSendResponse batchSend(MailtrapBatchMail mailtrapBatchMail) { + if (sendingContextHolder.isBulk()) { + return bulkSendingApi.emails().batchSend(mailtrapBatchMail); + } else if (sendingContextHolder.isSandbox()) { + return testingApi.emails().batchSend(mailtrapBatchMail, sendingContextHolder.getInboxId()); + } else { + return sendingApi.emails().batchSend(mailtrapBatchMail); + } + } + /** * Configures `send` method to use Bulk Sending API */ diff --git a/src/main/java/io/mailtrap/model/request/emails/BatchEmailBase.java b/src/main/java/io/mailtrap/model/request/emails/BatchEmailBase.java new file mode 100644 index 0000000..1532b5c --- /dev/null +++ b/src/main/java/io/mailtrap/model/request/emails/BatchEmailBase.java @@ -0,0 +1,67 @@ +package io.mailtrap.model.request.emails; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; +import java.util.Map; + +@Getter +@Setter +@Builder +public class BatchEmailBase { + + private Address from; + + @JsonProperty("reply_to") + private Address replyTo; + + @Size(min = 1) + private String subject; + + /** + * Can be used alongside with {@link #html} as a fallback option. + * Required in the absence of {@link #html} + */ + private String text; + + /** + * Can be used alongside with {@link #text} as a fallback option. + * Required in the absence of {@link #text} + */ + private String html; + + @Valid + private List attachments; + + /** + * 'Content-Transfer-Encoding' header will be ignored and replaced with 'quoted-printable' + */ + private Map headers; + + @Size(max = 255) + private String category; + + /** + * Values that are specific to the entire send that will be carried along with the email and its activity data + */ + @JsonProperty("custom_properties") + private Map customVariables; + + /** + * Should NOT be used if {@link #subject}, {@link #text} or {@link #html} is used + */ + @JsonProperty("template_uuid") + private String templateUuid; + + /** + * Should be sent if {@link #templateUuid} is used + */ + @JsonProperty("template_variables") + private Map templateVariables; + +} diff --git a/src/main/java/io/mailtrap/model/request/emails/MailtrapBatchMail.java b/src/main/java/io/mailtrap/model/request/emails/MailtrapBatchMail.java new file mode 100644 index 0000000..c019aa2 --- /dev/null +++ b/src/main/java/io/mailtrap/model/request/emails/MailtrapBatchMail.java @@ -0,0 +1,19 @@ +package io.mailtrap.model.request.emails; + +import io.mailtrap.model.AbstractModel; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@Builder +public class MailtrapBatchMail extends AbstractModel { + + private BatchEmailBase base; + + private List requests; + +} diff --git a/src/main/java/io/mailtrap/model/response/emails/BatchSendDetails.java b/src/main/java/io/mailtrap/model/response/emails/BatchSendDetails.java new file mode 100644 index 0000000..bda1c33 --- /dev/null +++ b/src/main/java/io/mailtrap/model/response/emails/BatchSendDetails.java @@ -0,0 +1,17 @@ +package io.mailtrap.model.response.emails; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class BatchSendDetails { + + private boolean success; + + @JsonProperty("message_ids") + private List messageIds; + + private List errors; +} diff --git a/src/main/java/io/mailtrap/model/response/emails/BatchSendResponse.java b/src/main/java/io/mailtrap/model/response/emails/BatchSendResponse.java new file mode 100644 index 0000000..6beb477 --- /dev/null +++ b/src/main/java/io/mailtrap/model/response/emails/BatchSendResponse.java @@ -0,0 +1,16 @@ +package io.mailtrap.model.response.emails; + +import lombok.Data; + +import java.util.List; + +@Data +public class BatchSendResponse { + + private boolean success; + + private List responses; + + private List errors; + +} diff --git a/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java b/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java index 966edba..bd83291 100644 --- a/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java +++ b/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java @@ -4,7 +4,9 @@ import io.mailtrap.config.MailtrapConfig; import io.mailtrap.exception.InvalidRequestBodyException; import io.mailtrap.factory.MailtrapClientFactory; +import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; +import io.mailtrap.model.response.emails.BatchSendResponse; import io.mailtrap.model.response.emails.SendResponse; import io.mailtrap.testutils.BaseSendTest; import io.mailtrap.testutils.DataMock; @@ -22,21 +24,29 @@ class BulkEmailsImplTest extends BaseSendTest { @BeforeEach public void init() { TestHttpClient httpClient = new TestHttpClient(List.of( - DataMock.build( - Constants.BULK_SENDING_HOST + "/api/send", - "POST", "api/emails/sendRequest.json", "api/emails/sendResponse.json" - ), - DataMock.build( - Constants.BULK_SENDING_HOST + "/api/send", - "POST", "api/emails/sendRequestFromTemplate.json", "api/emails/sendResponse.json" - ) + DataMock.build( + Constants.BULK_SENDING_HOST + "/api/send", + "POST", "api/emails/sendRequest.json", "api/emails/sendResponse.json" + ), + DataMock.build( + Constants.BULK_SENDING_HOST + "/api/send", + "POST", "api/emails/sendRequestFromTemplate.json", "api/emails/sendResponse.json" + ), + DataMock.build( + Constants.BULK_SENDING_HOST + "/api/batch", + "POST", "api/emails/batchSendRequest.json", "api/emails/batchSendResponse.json" + ), + DataMock.build( + Constants.BULK_SENDING_HOST + "/api/batch", + "POST", "api/emails/batchSendRequestFromTemplate.json", "api/emails/batchSendResponse.json" + ) )); MailtrapConfig testConfig = new MailtrapConfig.Builder() - .httpClient(httpClient) - .token("dummy_token") - .bulk(true) - .build(); + .httpClient(httpClient) + .token("dummy_token") + .bulk(true) + .build(); bulkEmails = MailtrapClientFactory.createMailtrapClient(testConfig).bulkSendingApi().emails(); } @@ -123,4 +133,47 @@ void send_ValidMailFromTemplate_SuccessResponse() { assertTrue(response.isSuccess()); assertEquals("11111", response.getMessageIds().get(0)); } + + @Test + void batchSend_ValidMail_SuccessResponse() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder().requests(List.of(createValidTestMail())).build(); + + // Perform call + BatchSendResponse response = bulkEmails.batchSend(batchMail); + + // Assert + assertTrue(response.isSuccess()); + assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); + } + + @Test + void batchSend_ValidMailFromTemplate_SuccessResponse() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder().requests(List.of(createTestMailFromTemplate())).build(); + + // Perform call + BatchSendResponse response = bulkEmails.batchSend(batchMail); + + // Assert + assertTrue(response.isSuccess()); + assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); + } + + @Test + void batchSend_NullableMail_ThrowsInvalidRequestBodyException() { + // Assert + InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> bulkEmails.batchSend(null)); + assertEquals(BATCH_MAIL_MUST_NOT_BE_NULL, exception.getMessage()); + } + + @Test + void batchSend_MailWithTemplateUuidAndText_ThrowsInvalidRequestBodyException() { + // Set up invalid data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder().requests(List.of(createTestMailWithTemplateUuidAndText())).build(); + + // Assert + InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> bulkEmails.batchSend(batchMail)); + assertEquals(TEMPLATE_UUID_IS_USED_SUBJECT_AND_TEXT_AND_HTML_SHOULD_BE_EMPTY, exception.getMessage()); + } } diff --git a/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java b/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java index e24dcd8..366baed 100644 --- a/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java +++ b/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java @@ -4,7 +4,9 @@ import io.mailtrap.config.MailtrapConfig; import io.mailtrap.exception.InvalidRequestBodyException; import io.mailtrap.factory.MailtrapClientFactory; +import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; +import io.mailtrap.model.response.emails.BatchSendResponse; import io.mailtrap.model.response.emails.SendResponse; import io.mailtrap.testutils.BaseSendTest; import io.mailtrap.testutils.DataMock; @@ -23,20 +25,28 @@ class SendingEmailsImplTest extends BaseSendTest { @BeforeEach public void init() { TestHttpClient httpClient = new TestHttpClient(List.of( - DataMock.build( - Constants.EMAIL_SENDING_SEND_HOST + "/api/send", - "POST", "api/emails/sendRequest.json", "api/emails/sendResponse.json" - ), - DataMock.build( - Constants.EMAIL_SENDING_SEND_HOST + "/api/send", - "POST", "api/emails/sendRequestFromTemplate.json", "api/emails/sendResponse.json" - ) + DataMock.build( + Constants.EMAIL_SENDING_SEND_HOST + "/api/send", + "POST", "api/emails/sendRequest.json", "api/emails/sendResponse.json" + ), + DataMock.build( + Constants.EMAIL_SENDING_SEND_HOST + "/api/send", + "POST", "api/emails/sendRequestFromTemplate.json", "api/emails/sendResponse.json" + ), + DataMock.build( + Constants.EMAIL_SENDING_SEND_HOST + "/api/batch", + "POST", "api/emails/batchSendRequest.json", "api/emails/batchSendResponse.json" + ), + DataMock.build( + Constants.EMAIL_SENDING_SEND_HOST + "/api/batch", + "POST", "api/emails/batchSendRequestFromTemplate.json", "api/emails/batchSendResponse.json" + ) )); MailtrapConfig testConfig = new MailtrapConfig.Builder() - .httpClient(httpClient) - .token("dummy_token") - .build(); + .httpClient(httpClient) + .token("dummy_token") + .build(); sendApi = MailtrapClientFactory.createMailtrapClient(testConfig).sendingApi().emails(); } @@ -123,4 +133,47 @@ void send_ValidMailFromTemplate_SuccessResponse() { assertTrue(response.isSuccess()); assertEquals("11111", response.getMessageIds().get(0)); } + + @Test + void batchSend_ValidMail_SuccessResponse() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder().requests(List.of(createValidTestMail())).build(); + + // Perform call + BatchSendResponse response = sendApi.batchSend(batchMail); + + // Assert + assertTrue(response.isSuccess()); + assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); + } + + @Test + void batchSend_ValidMailFromTemplate_SuccessResponse() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder().requests(List.of(createTestMailFromTemplate())).build(); + + // Perform call + BatchSendResponse response = sendApi.batchSend(batchMail); + + // Assert + assertTrue(response.isSuccess()); + assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); + } + + @Test + void batchSend_NullableMail_ThrowsInvalidRequestBodyException() { + // Assert + InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> sendApi.batchSend(null)); + assertEquals(BATCH_MAIL_MUST_NOT_BE_NULL, exception.getMessage()); + } + + @Test + void batchSend_MailWithTemplateUuidAndText_ThrowsInvalidRequestBodyException() { + // Set up invalid data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder().requests(List.of(createTestMailWithTemplateUuidAndText())).build(); + + // Assert + InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> sendApi.batchSend(batchMail)); + assertEquals(TEMPLATE_UUID_IS_USED_SUBJECT_AND_TEXT_AND_HTML_SHOULD_BE_EMPTY, exception.getMessage()); + } } diff --git a/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java b/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java index d96ccf6..6ff123a 100644 --- a/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java +++ b/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java @@ -4,7 +4,9 @@ import io.mailtrap.config.MailtrapConfig; import io.mailtrap.exception.InvalidRequestBodyException; import io.mailtrap.factory.MailtrapClientFactory; +import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; +import io.mailtrap.model.response.emails.BatchSendResponse; import io.mailtrap.model.response.emails.SendResponse; import io.mailtrap.testutils.BaseSendTest; import io.mailtrap.testutils.DataMock; @@ -30,6 +32,14 @@ public void init() { DataMock.build( Constants.EMAIL_TESTING_SEND_HOST + "/api/send/" + INBOX_ID, "POST", "api/emails/sendRequestFromTemplate.json", "api/emails/sendResponse.json" + ), + DataMock.build( + Constants.EMAIL_TESTING_SEND_HOST + "/api/batch/" + INBOX_ID, + "POST", "api/emails/batchSendRequest.json", "api/emails/batchSendResponse.json" + ), + DataMock.build( + Constants.EMAIL_TESTING_SEND_HOST + "/api/batch/" + INBOX_ID, + "POST", "api/emails/batchSendRequestFromTemplate.json", "api/emails/batchSendResponse.json" ) )); @@ -126,4 +136,48 @@ void send_ValidMailFromTemplate_SuccessResponse() { assertEquals("11111", response.getMessageIds().get(0)); } + @Test + void batchSend_ValidMail_SuccessResponse() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder().requests(List.of(createValidTestMail())).build(); + + // Perform call + BatchSendResponse response = testingApi.batchSend(batchMail, INBOX_ID); + + // Assert + assertTrue(response.isSuccess()); + assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); + } + + @Test + void batchSend_ValidMailFromTemplate_SuccessResponse() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder().requests(List.of(createTestMailFromTemplate())).build(); + + // Perform call + BatchSendResponse response = testingApi.batchSend(batchMail, INBOX_ID); + + // Assert + assertTrue(response.isSuccess()); + assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); + } + + @Test + void batchSend_NullableMail_ThrowsInvalidRequestBodyException() { + // Assert + InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> testingApi.batchSend(null, INBOX_ID)); + assertEquals(BATCH_MAIL_MUST_NOT_BE_NULL, exception.getMessage()); + } + + @Test + void batchSend_MailWithTemplateUuidAndText_ThrowsInvalidRequestBodyException() { + // Set up invalid data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder().requests(List.of(createTestMailWithTemplateUuidAndText())).build(); + + + // Assert + InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> testingApi.batchSend(batchMail, INBOX_ID)); + assertEquals(TEMPLATE_UUID_IS_USED_SUBJECT_AND_TEXT_AND_HTML_SHOULD_BE_EMPTY, exception.getMessage()); + } + } diff --git a/src/test/java/io/mailtrap/client/MailtrapClientTest.java b/src/test/java/io/mailtrap/client/MailtrapClientTest.java index 0d746cd..797243b 100644 --- a/src/test/java/io/mailtrap/client/MailtrapClientTest.java +++ b/src/test/java/io/mailtrap/client/MailtrapClientTest.java @@ -4,7 +4,9 @@ import io.mailtrap.config.MailtrapConfig; import io.mailtrap.exception.BaseMailtrapException; import io.mailtrap.factory.MailtrapClientFactory; +import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; +import io.mailtrap.model.response.emails.BatchSendResponse; import io.mailtrap.model.response.emails.SendResponse; import io.mailtrap.testutils.BaseSendTest; import io.mailtrap.testutils.DataMock; @@ -24,20 +26,29 @@ class MailtrapClientTest extends BaseSendTest { @BeforeEach void setUp() { TestHttpClient httpClient = new TestHttpClient(List.of( - DataMock.build(Constants.EMAIL_TESTING_SEND_HOST + "/api/send/" + INBOX_ID, "POST", - "api/emails/sendRequest.json", "api/emails/sendResponse.json"), + DataMock.build(Constants.EMAIL_TESTING_SEND_HOST + "/api/send/" + INBOX_ID, "POST", + "api/emails/sendRequest.json", "api/emails/sendResponse.json"), - DataMock.build(Constants.BULK_SENDING_HOST + "/api/send", "POST", - "api/emails/sendRequest.json", "api/emails/sendResponse.json"), + DataMock.build(Constants.BULK_SENDING_HOST + "/api/send", "POST", + "api/emails/sendRequest.json", "api/emails/sendResponse.json"), - DataMock.build(Constants.EMAIL_SENDING_SEND_HOST + "/api/send", "POST", - "api/emails/sendRequest.json", "api/emails/sendResponse.json") + DataMock.build(Constants.EMAIL_SENDING_SEND_HOST + "/api/send", "POST", + "api/emails/sendRequest.json", "api/emails/sendResponse.json"), + + DataMock.build(Constants.EMAIL_TESTING_SEND_HOST + "/api/batch/" + INBOX_ID, "POST", + "api/emails/batchSendRequest.json", "api/emails/batchSendResponse.json"), + + DataMock.build(Constants.BULK_SENDING_HOST + "/api/batch", "POST", + "api/emails/batchSendRequest.json", "api/emails/batchSendResponse.json"), + + DataMock.build(Constants.EMAIL_SENDING_SEND_HOST + "/api/batch", "POST", + "api/emails/batchSendRequest.json", "api/emails/batchSendResponse.json") )); MailtrapConfig mailtrapConfig = new MailtrapConfig.Builder() - .token("dummy-token") - .httpClient(httpClient) - .build(); + .token("dummy-token") + .httpClient(httpClient) + .build(); mailtrapClient = MailtrapClientFactory.createMailtrapClient(mailtrapConfig); } @@ -82,13 +93,56 @@ void test_send_success() { assertEquals("11111", response.getMessageIds().get(0)); } + @Test + void test_batchSendBulk_success() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder().requests(List.of(createValidTestMail())).build(); + + mailtrapClient.switchToBulkSendingApi(); + + // Call + BatchSendResponse response = mailtrapClient.batchSend(batchMail); + + // Assert + assertEquals(1, response.getResponses().size()); + assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); + } + + @Test + void test_batchSendSandbox_success() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder().requests(List.of(createValidTestMail())).build(); + + mailtrapClient.switchToEmailTestingApi(INBOX_ID); + + // Call + BatchSendResponse response = mailtrapClient.batchSend(batchMail); + + // Assert + assertEquals(1, response.getResponses().size()); + assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); + } + + @Test + void test_batchSend_success() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder().requests(List.of(createValidTestMail())).build(); + + // Call + BatchSendResponse response = mailtrapClient.batchSend(batchMail); + + // Assert + assertEquals(1, response.getResponses().size()); + assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); + } + @Test void test_bulkAndSandboxTrue_ThrowsBaseMailtrapException() { // Set up test data and call BaseMailtrapException exception = assertThrows(BaseMailtrapException.class, () -> new MailtrapConfig.Builder() - .bulk(true) - .sandbox(true) - .build()); + .bulk(true) + .sandbox(true) + .build()); // Assert assertEquals(BULK_AND_SANDBOX_TRUE_IN_SENDING_CONFIG, exception.getMessage()); @@ -98,9 +152,9 @@ void test_bulkAndSandboxTrue_ThrowsBaseMailtrapException() { void test_sandboxTrueAndInboxIdIsNull_ThrowsBaseMailtrapException() { // Set up test data and call BaseMailtrapException exception = assertThrows(BaseMailtrapException.class, () -> new MailtrapConfig.Builder() - .sandbox(true) - .inboxId(null) - .build()); + .sandbox(true) + .inboxId(null) + .build()); // Assert assertEquals(INBOX_ID_REQUIRED, exception.getMessage()); diff --git a/src/test/java/io/mailtrap/testutils/BaseSendTest.java b/src/test/java/io/mailtrap/testutils/BaseSendTest.java index caf3b9b..0603f81 100644 --- a/src/test/java/io/mailtrap/testutils/BaseSendTest.java +++ b/src/test/java/io/mailtrap/testutils/BaseSendTest.java @@ -18,6 +18,7 @@ public class BaseSendTest { protected final String TEMPLATE_UUID_IS_USED_SUBJECT_AND_TEXT_AND_HTML_SHOULD_BE_EMPTY = "When templateUuid is used, subject, text, and html must not be used"; protected final String TEMPLATE_VARIABLES_SHOULD_BE_USED_WITH_TEMPLATE_UUID = "Mail templateVariables must only be used with templateUuid"; protected final String MAIL_MUST_NOT_BE_NULL = "Mail must not be null"; + protected final String BATCH_MAIL_MUST_NOT_BE_NULL = "BatchMail must not be null"; private Address getAddress(String email, String name) { return new Address(email, name); diff --git a/src/test/resources/api/emails/batchSendRequest.json b/src/test/resources/api/emails/batchSendRequest.json new file mode 100644 index 0000000..b83130f --- /dev/null +++ b/src/test/resources/api/emails/batchSendRequest.json @@ -0,0 +1,26 @@ +{ + "requests": [ + { + "from": { + "name": "John Doe", + "email": "sender@example.com" + }, + "to": [ + { + "name": "Jane Doe", + "email": "receiver@example.com" + } + ], + "attachments": [ + { + "content": "c2FtcGxlIHRleHQgaW4gdGV4dCBmaWxl", + "type": "text/plain", + "filename": "attachment.txt" + } + ], + "subject": "Sample valid mail subject", + "text": "Sample valid mail text", + "html": "Test HTML" + } + ] +} diff --git a/src/test/resources/api/emails/batchSendRequestFromTemplate.json b/src/test/resources/api/emails/batchSendRequestFromTemplate.json new file mode 100644 index 0000000..5defe39 --- /dev/null +++ b/src/test/resources/api/emails/batchSendRequestFromTemplate.json @@ -0,0 +1,25 @@ +{ + "requests": [ + { + "from": { + "email": "sender@example.com" + }, + "to": [ + { + "email": "receiver@example.com" + } + ], + "attachments": [ + { + "content": "c2FtcGxlIHRleHQgaW4gdGV4dCBmaWxl", + "type": "text/plain", + "filename": "attachment.txt" + } + ], + "template_uuid": "imagine-this-is-uuid", + "template_variables": { + "user_name": "John Doe" + } + } + ] +} diff --git a/src/test/resources/api/emails/batchSendResponse.json b/src/test/resources/api/emails/batchSendResponse.json new file mode 100644 index 0000000..5ceedce --- /dev/null +++ b/src/test/resources/api/emails/batchSendResponse.json @@ -0,0 +1,13 @@ +{ + "success": true, + "responses": [ + { + "success": true, + "message_ids": [ + "22222" + ], + "errors": [] + } + ], + "errors": [] +} From f752d2ea03c80fdc47cad758412d9baa5c5d8635 Mon Sep 17 00:00:00 2001 From: vtasun Date: Thu, 11 Sep 2025 00:49:41 +0300 Subject: [PATCH 2/5] Code review updates, improved mail validation --- .../java/io/mailtrap/examples/bulk/Batch.java | 2 +- .../io/mailtrap/examples/sending/Batch.java | 2 +- .../io/mailtrap/examples/testing/Batch.java | 2 +- .../api/apiresource/SendApiResource.java | 23 +++++++++++++++---- .../model/request/emails/BatchEmailBase.java | 2 +- .../request/emails/MailtrapBatchMail.java | 7 ++++++ .../api/bulkemails/BulkEmailsImplTest.java | 10 ++++++++ .../sendingemails/SendingEmailsImplTest.java | 10 ++++++++ .../testingemails/TestingEmailsImplTest.java | 10 ++++++++ .../io/mailtrap/testutils/BaseSendTest.java | 14 +++++++++++ 10 files changed, 73 insertions(+), 9 deletions(-) diff --git a/examples/java/io/mailtrap/examples/bulk/Batch.java b/examples/java/io/mailtrap/examples/bulk/Batch.java index 2348731..65bc1ef 100644 --- a/examples/java/io/mailtrap/examples/bulk/Batch.java +++ b/examples/java/io/mailtrap/examples/bulk/Batch.java @@ -10,7 +10,7 @@ import java.util.List; import java.util.Map; -public class Bulk { +public class Batch { private static final String TOKEN = ""; private static final String SENDER_EMAIL = "sender@domain.com"; diff --git a/examples/java/io/mailtrap/examples/sending/Batch.java b/examples/java/io/mailtrap/examples/sending/Batch.java index e3799ec..6a58065 100644 --- a/examples/java/io/mailtrap/examples/sending/Batch.java +++ b/examples/java/io/mailtrap/examples/sending/Batch.java @@ -10,7 +10,7 @@ import java.util.List; import java.util.Map; -public class Bulk { +public class Batch { private static final String TOKEN = ""; private static final String SENDER_EMAIL = "sender@domain.com"; diff --git a/examples/java/io/mailtrap/examples/testing/Batch.java b/examples/java/io/mailtrap/examples/testing/Batch.java index d6e017e..f5b46d4 100644 --- a/examples/java/io/mailtrap/examples/testing/Batch.java +++ b/examples/java/io/mailtrap/examples/testing/Batch.java @@ -38,7 +38,7 @@ public static void main(String[] args) { final var batchMail = MailtrapBatchMail.builder() // Optionally you can add this `base` object - if you have some common data across emails // Each property can be overridden in `requests` for individual emails - .base(BatchEmailBase.builder().subject("Base Subject for all emails").build()) + .base(BatchEmailBase.builder().templateUuid("base-template-uuid").build()) .requests(List.of(mail)) .build(); diff --git a/src/main/java/io/mailtrap/api/apiresource/SendApiResource.java b/src/main/java/io/mailtrap/api/apiresource/SendApiResource.java index 795c453..6a563b4 100644 --- a/src/main/java/io/mailtrap/api/apiresource/SendApiResource.java +++ b/src/main/java/io/mailtrap/api/apiresource/SendApiResource.java @@ -8,6 +8,8 @@ import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; +import java.util.Objects; + /** * Abstract class representing a resource for sending emails via Mailtrap API. */ @@ -17,10 +19,16 @@ protected SendApiResource(MailtrapConfig config, CustomValidator customValidator super(config, customValidator); } - protected void assertBatchMailNotNull(MailtrapBatchMail batchMail){ + protected void assertBatchMailNotNull(MailtrapBatchMail batchMail) { if (batchMail == null) { throw new InvalidRequestBodyException("BatchMail must not be null"); } + if (batchMail.getRequests() == null || batchMail.getRequests().isEmpty()) { + throw new InvalidRequestBodyException("BatchMail.requests must not be null or empty"); + } + if (batchMail.getRequests().stream().anyMatch(Objects::isNull)) { + throw new InvalidRequestBodyException("BatchMail.requests must not contain null items"); + } } /** @@ -36,9 +44,9 @@ protected void validateMailPayload(MailtrapMail mail) throws InvalidRequestBodyE } // Check if all three subject, text, and html are empty - boolean isSubjectTextHtmlEmpty = StringUtils.isEmpty(mail.getSubject()) - && StringUtils.isEmpty(mail.getText()) - && StringUtils.isEmpty(mail.getHtml()); + boolean isSubjectTextHtmlEmpty = StringUtils.isBlank(mail.getSubject()) + && StringUtils.isBlank(mail.getText()) + && StringUtils.isBlank(mail.getHtml()); // Validate depending on whether the templateUuid is set if (StringUtils.isEmpty(mail.getTemplateUuid())) { @@ -65,9 +73,14 @@ private void validateWithoutTemplate(MailtrapMail mail, boolean isSubjectTextHtm } // Ensure the subject is not empty - if (StringUtils.isEmpty(mail.getSubject())) { + if (StringUtils.isBlank(mail.getSubject())) { throw new InvalidRequestBodyException("Subject must not be null or empty"); } + + // Ensure at least one of text or html is present + if (StringUtils.isBlank(mail.getText()) && StringUtils.isBlank(mail.getHtml())) { + throw new InvalidRequestBodyException("Mail must have subject and either text or html when templateUuid is not provided"); + } } private void validateWithTemplate(MailtrapMail mail) throws InvalidRequestBodyException { diff --git a/src/main/java/io/mailtrap/model/request/emails/BatchEmailBase.java b/src/main/java/io/mailtrap/model/request/emails/BatchEmailBase.java index 1532b5c..cbdd952 100644 --- a/src/main/java/io/mailtrap/model/request/emails/BatchEmailBase.java +++ b/src/main/java/io/mailtrap/model/request/emails/BatchEmailBase.java @@ -49,7 +49,7 @@ public class BatchEmailBase { /** * Values that are specific to the entire send that will be carried along with the email and its activity data */ - @JsonProperty("custom_properties") + @JsonProperty("custom_variables") private Map customVariables; /** diff --git a/src/main/java/io/mailtrap/model/request/emails/MailtrapBatchMail.java b/src/main/java/io/mailtrap/model/request/emails/MailtrapBatchMail.java index c019aa2..cc27f41 100644 --- a/src/main/java/io/mailtrap/model/request/emails/MailtrapBatchMail.java +++ b/src/main/java/io/mailtrap/model/request/emails/MailtrapBatchMail.java @@ -1,6 +1,9 @@ package io.mailtrap.model.request.emails; import io.mailtrap.model.AbstractModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -12,8 +15,12 @@ @Builder public class MailtrapBatchMail extends AbstractModel { + @Valid private BatchEmailBase base; + @NotNull + @Size(min = 1) + @Valid private List requests; } diff --git a/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java b/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java index bd83291..b08ad0a 100644 --- a/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java +++ b/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java @@ -101,6 +101,16 @@ void send_MailWithTemplateVariablesAndHtml_ThrowsInvalidRequestBodyException() { assertEquals(TEMPLATE_VARIABLES_SHOULD_BE_USED_WITH_TEMPLATE_UUID, exception.getMessage()); } + @Test + void send_MailWithSubjectAndNoTextNoHtml_ThrowsInvalidRequestBodyException() { + // Set up invalid data + MailtrapMail mail = createTestMailWithSubjectAndNoTextAndNoHtml(); + + // Assert + InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> bulkEmails.send(mail)); + assertEquals(MAIL_MUST_HAVE_SUBJECT_AND_EITHER_TEXT_OR_HTML, exception.getMessage()); + } + @Test void send_NullableMail_ThrowsInvalidRequestBodyException() { // Assert diff --git a/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java b/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java index 366baed..00c7223 100644 --- a/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java +++ b/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java @@ -101,6 +101,16 @@ void send_MailWithTemplateVariablesAndHtml_ThrowsInvalidRequestBodyException() { assertEquals(TEMPLATE_VARIABLES_SHOULD_BE_USED_WITH_TEMPLATE_UUID, exception.getMessage()); } + @Test + void send_MailWithSubjectAndNoTextNoHtml_ThrowsInvalidRequestBodyException() { + // Set up invalid data + MailtrapMail mail = createTestMailWithSubjectAndNoTextAndNoHtml(); + + // Assert + InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> sendApi.send(mail)); + assertEquals(MAIL_MUST_HAVE_SUBJECT_AND_EITHER_TEXT_OR_HTML, exception.getMessage()); + } + @Test void send_NullableMail_ThrowsInvalidRequestBodyException() { // Assert diff --git a/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java b/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java index 6ff123a..30283b0 100644 --- a/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java +++ b/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java @@ -103,6 +103,16 @@ void send_MailWithTemplateVariablesAndHtml_ThrowsInvalidRequestBodyException() { assertEquals(TEMPLATE_VARIABLES_SHOULD_BE_USED_WITH_TEMPLATE_UUID, exception.getMessage()); } + @Test + void send_MailWithSubjectAndNoTextNoHtml_ThrowsInvalidRequestBodyException() { + // Set up invalid data + MailtrapMail mail = createTestMailWithSubjectAndNoTextAndNoHtml(); + + // Assert + InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> testingApi.send(mail, INBOX_ID)); + assertEquals(MAIL_MUST_HAVE_SUBJECT_AND_EITHER_TEXT_OR_HTML, exception.getMessage()); + } + @Test void send_NullableMail_ThrowsInvalidRequestBodyException() { // Assert diff --git a/src/test/java/io/mailtrap/testutils/BaseSendTest.java b/src/test/java/io/mailtrap/testutils/BaseSendTest.java index 0603f81..0114a38 100644 --- a/src/test/java/io/mailtrap/testutils/BaseSendTest.java +++ b/src/test/java/io/mailtrap/testutils/BaseSendTest.java @@ -17,6 +17,7 @@ public class BaseSendTest { protected final String TEMPLATE_UUID_OR_SUBJECT_AND_TEXT_OR_HTML_MUST_NOT_BE_EMPTY = "Mail must have subject and either text or html when templateUuid is not provided"; protected final String TEMPLATE_UUID_IS_USED_SUBJECT_AND_TEXT_AND_HTML_SHOULD_BE_EMPTY = "When templateUuid is used, subject, text, and html must not be used"; protected final String TEMPLATE_VARIABLES_SHOULD_BE_USED_WITH_TEMPLATE_UUID = "Mail templateVariables must only be used with templateUuid"; + protected final String MAIL_MUST_HAVE_SUBJECT_AND_EITHER_TEXT_OR_HTML = "Mail must have subject and either text or html when templateUuid is not provided"; protected final String MAIL_MUST_NOT_BE_NULL = "Mail must not be null"; protected final String BATCH_MAIL_MUST_NOT_BE_NULL = "BatchMail must not be null"; @@ -74,6 +75,19 @@ protected MailtrapMail createTestMailWithoutTemplateUuidAndSubjectAndTextAndHtml .build(); } + protected MailtrapMail createTestMailWithSubjectAndNoTextAndNoHtml() { + Address from = getAddress("sender@example.com", "John Doe"); + Address to = getAddress("receiver@example.com", "Jane Doe"); + EmailAttachment attachment = getAttachment(); + + return MailtrapMail.builder() + .from(from) + .subject("Sample invalidvalid mail subject") + .to(List.of(to)) + .attachments(List.of(attachment)) + .build(); + } + protected MailtrapMail createTestMailWithTemplateUuidAndText() { Address from = getAddress("sender@example.com", null); Address to = getAddress("receiver@example.com", null); From 632304f96609fe3846b3c07cd5223ca277bddbe1 Mon Sep 17 00:00:00 2001 From: vtasun Date: Sat, 13 Sep 2025 01:58:47 +0300 Subject: [PATCH 3/5] Enhanced validation taking `base` into account for batch send, added unit-tests with `base` --- .../api/apiresource/SendApiResource.java | 120 +++++++++++------- .../api/bulkemails/BulkEmailsImpl.java | 6 +- .../api/sendingemails/SendingEmailsImpl.java | 6 +- .../api/testingemails/TestingEmailsImpl.java | 6 +- .../InvalidRequestBodyException.java | 4 + .../model/mailvalidation/ContentView.java | 21 +++ .../model/mailvalidation/MailContentView.java | 41 ++++++ .../ResolvedMailContentView.java | 39 ++++++ .../mailvalidation/ResolvedMailView.java | 90 +++++++++++++ .../api/bulkemails/BulkEmailsImplTest.java | 51 ++++++++ .../sendingemails/SendingEmailsImplTest.java | 51 ++++++++ .../testingemails/TestingEmailsImplTest.java | 93 +++++++++++--- .../io/mailtrap/testutils/BaseSendTest.java | 27 ++++ ...atchSendWithBaseSubjectAndTextRequest.json | 27 ++++ .../batchSendWithBaseSubjectRequest.json | 28 ++++ 15 files changed, 526 insertions(+), 84 deletions(-) create mode 100644 src/main/java/io/mailtrap/model/mailvalidation/ContentView.java create mode 100644 src/main/java/io/mailtrap/model/mailvalidation/MailContentView.java create mode 100644 src/main/java/io/mailtrap/model/mailvalidation/ResolvedMailContentView.java create mode 100644 src/main/java/io/mailtrap/model/mailvalidation/ResolvedMailView.java create mode 100644 src/test/resources/api/emails/batchSendWithBaseSubjectAndTextRequest.json create mode 100644 src/test/resources/api/emails/batchSendWithBaseSubjectRequest.json diff --git a/src/main/java/io/mailtrap/api/apiresource/SendApiResource.java b/src/main/java/io/mailtrap/api/apiresource/SendApiResource.java index 6a563b4..0220021 100644 --- a/src/main/java/io/mailtrap/api/apiresource/SendApiResource.java +++ b/src/main/java/io/mailtrap/api/apiresource/SendApiResource.java @@ -3,6 +3,11 @@ import io.mailtrap.CustomValidator; import io.mailtrap.config.MailtrapConfig; import io.mailtrap.exception.InvalidRequestBodyException; +import io.mailtrap.model.mailvalidation.ContentView; +import io.mailtrap.model.mailvalidation.MailContentView; +import io.mailtrap.model.mailvalidation.ResolvedMailContentView; +import io.mailtrap.model.mailvalidation.ResolvedMailView; +import io.mailtrap.model.request.emails.BatchEmailBase; import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; import org.apache.commons.collections4.MapUtils; @@ -19,74 +24,93 @@ protected SendApiResource(MailtrapConfig config, CustomValidator customValidator super(config, customValidator); } - protected void assertBatchMailNotNull(MailtrapBatchMail batchMail) { - if (batchMail == null) { - throw new InvalidRequestBodyException("BatchMail must not be null"); - } - if (batchMail.getRequests() == null || batchMail.getRequests().isEmpty()) { - throw new InvalidRequestBodyException("BatchMail.requests must not be null or empty"); - } - if (batchMail.getRequests().stream().anyMatch(Objects::isNull)) { - throw new InvalidRequestBodyException("BatchMail.requests must not contain null items"); - } - } - /** * Validates the request body of an email message and throws an exception if it is invalid. * * @param mail The email message to be validated. * @throws InvalidRequestBodyException If the request body is invalid. */ - protected void validateMailPayload(MailtrapMail mail) throws InvalidRequestBodyException { - // Check if the mail object itself is null + protected void validateMailPayload(MailtrapMail mail) { if (mail == null) { throw new InvalidRequestBodyException("Mail must not be null"); } - // Check if all three subject, text, and html are empty - boolean isSubjectTextHtmlEmpty = StringUtils.isBlank(mail.getSubject()) - && StringUtils.isBlank(mail.getText()) - && StringUtils.isBlank(mail.getHtml()); - - // Validate depending on whether the templateUuid is set - if (StringUtils.isEmpty(mail.getTemplateUuid())) { - // Validation for the scenario where templateUuid is not provided - validateWithoutTemplate(mail, isSubjectTextHtmlEmpty); - } else { - // Validation for the scenario where templateUuid is provided - validateWithTemplate(mail); - } - - // Additional validation logic (assumed to be provided by the user) + // Perform bean validation (NotNull, etc.) validateRequestBodyAndThrowException(mail); + + // Validate subject/text/html/templateUuid + validateContentRules(MailContentView.of(mail)); } - private void validateWithoutTemplate(MailtrapMail mail, boolean isSubjectTextHtmlEmpty) throws InvalidRequestBodyException { - // Ensure that at least subject, text, or html is provided if templateUuid is not set - if (isSubjectTextHtmlEmpty) { - throw new InvalidRequestBodyException("Mail must have subject and either text or html when templateUuid is not provided"); - } + /** + * Validates the request body of batch email and throws an exception if it is invalid. + * + * @param batch batch request to be validated. + * @throws InvalidRequestBodyException If the request body is invalid. + */ + protected void validateBatchPayload(MailtrapBatchMail batch) { + assertBatchMailNotNull(batch); - // Ensure templateVariables are not used if templateUuid is not set - if (MapUtils.isNotEmpty(mail.getTemplateVariables())) { - throw new InvalidRequestBodyException("Mail templateVariables must only be used with templateUuid"); - } + BatchEmailBase base = batch.getBase(); + + for (int i = 0; i < batch.getRequests().size(); i++) { + MailtrapMail mail = batch.getRequests().get(i); + ResolvedMailView mailView = new ResolvedMailView(base, mail); + + try { + // Perform bean validation (NotNull, etc.) + validateRequestBodyAndThrowException(mailView); + } catch (InvalidRequestBodyException e) { + throw new InvalidRequestBodyException("requests[" + i + "]: " + e.getMessage(), e); + } + + validateContentRules(ResolvedMailContentView.of(mailView)); - // Ensure the subject is not empty - if (StringUtils.isBlank(mail.getSubject())) { - throw new InvalidRequestBodyException("Subject must not be null or empty"); + if (mailView.getFrom() == null) { + throw new InvalidRequestBodyException("requests[" + i + "]: from is required (either in mail or base)"); + } } + } - // Ensure at least one of text or html is present - if (StringUtils.isBlank(mail.getText()) && StringUtils.isBlank(mail.getHtml())) { - throw new InvalidRequestBodyException("Mail must have subject and either text or html when templateUuid is not provided"); + private void assertBatchMailNotNull(MailtrapBatchMail batchMail) { + if (batchMail == null) { + throw new InvalidRequestBodyException("BatchMail must not be null"); } + if (batchMail.getRequests() == null || batchMail.getRequests().isEmpty()) { + throw new InvalidRequestBodyException("BatchMail.requests must not be null or empty"); + } + if (batchMail.getRequests().stream().anyMatch(Objects::isNull)) { + throw new InvalidRequestBodyException("BatchMail.requests must not contain null items"); + } + } - private void validateWithTemplate(MailtrapMail mail) throws InvalidRequestBodyException { - // Ensure that subject, text, and html are not used when templateUuid is set - if (StringUtils.isNotEmpty(mail.getText()) || StringUtils.isNotEmpty(mail.getHtml()) || StringUtils.isNotEmpty(mail.getSubject())) { - throw new InvalidRequestBodyException("When templateUuid is used, subject, text, and html must not be used"); + private void validateContentRules(ContentView v) { + boolean templateUuidBlank = StringUtils.isBlank(v.getTemplateUuid()); + + boolean subjectTextHtmlEmpty = StringUtils.isBlank(v.getSubject()) + && StringUtils.isBlank(v.getText()) + && StringUtils.isBlank(v.getHtml()); + + if (templateUuidBlank) { + if (subjectTextHtmlEmpty) { + throw new InvalidRequestBodyException("Mail must have subject and either text or html when templateUuid is not provided"); + } + if (MapUtils.isNotEmpty(v.getTemplateVariables())) { + throw new InvalidRequestBodyException("Mail templateVariables must only be used with templateUuid"); + } + if (StringUtils.isBlank(v.getSubject())) { + throw new InvalidRequestBodyException("Subject must not be null or empty"); + } + if (StringUtils.isBlank(v.getText()) && StringUtils.isBlank(v.getHtml())) { + throw new InvalidRequestBodyException("Mail must have subject and either text or html when templateUuid is not provided"); + } + } else { + if (StringUtils.isNotEmpty(v.getSubject()) + || StringUtils.isNotEmpty(v.getText()) + || StringUtils.isNotEmpty(v.getHtml())) + throw new InvalidRequestBodyException("When templateUuid is used, subject, text, and html must not be used"); } } + } diff --git a/src/main/java/io/mailtrap/api/bulkemails/BulkEmailsImpl.java b/src/main/java/io/mailtrap/api/bulkemails/BulkEmailsImpl.java index 3973037..c5ce8b0 100644 --- a/src/main/java/io/mailtrap/api/bulkemails/BulkEmailsImpl.java +++ b/src/main/java/io/mailtrap/api/bulkemails/BulkEmailsImpl.java @@ -34,11 +34,7 @@ public SendResponse send(MailtrapMail mail) { @Override public BatchSendResponse batchSend(MailtrapBatchMail mail) throws HttpException, InvalidRequestBodyException { - assertBatchMailNotNull(mail); - - mail - .getRequests() - .forEach(this::validateMailPayload); + validateBatchPayload(mail); return httpClient.post(apiHost + "/api/batch", mail, new RequestData(), BatchSendResponse.class); diff --git a/src/main/java/io/mailtrap/api/sendingemails/SendingEmailsImpl.java b/src/main/java/io/mailtrap/api/sendingemails/SendingEmailsImpl.java index 5b674e8..66a74d8 100644 --- a/src/main/java/io/mailtrap/api/sendingemails/SendingEmailsImpl.java +++ b/src/main/java/io/mailtrap/api/sendingemails/SendingEmailsImpl.java @@ -34,11 +34,7 @@ public SendResponse send(MailtrapMail mail) { @Override public BatchSendResponse batchSend(MailtrapBatchMail mail) throws HttpException, InvalidRequestBodyException { - assertBatchMailNotNull(mail); - - mail - .getRequests() - .forEach(this::validateMailPayload); + validateBatchPayload(mail); return httpClient.post(apiHost + "/api/batch", mail, new RequestData(), BatchSendResponse.class); diff --git a/src/main/java/io/mailtrap/api/testingemails/TestingEmailsImpl.java b/src/main/java/io/mailtrap/api/testingemails/TestingEmailsImpl.java index b95fb4f..5016b56 100644 --- a/src/main/java/io/mailtrap/api/testingemails/TestingEmailsImpl.java +++ b/src/main/java/io/mailtrap/api/testingemails/TestingEmailsImpl.java @@ -34,11 +34,7 @@ public SendResponse send(MailtrapMail mail, long inboxId) { @Override public BatchSendResponse batchSend(MailtrapBatchMail mail, long inboxId) throws HttpException, InvalidRequestBodyException { - assertBatchMailNotNull(mail); - - mail - .getRequests() - .forEach(this::validateMailPayload); + validateBatchPayload(mail); return httpClient.post(String.format(apiHost + "/api/batch/%d", inboxId), mail, new RequestData(), BatchSendResponse.class); diff --git a/src/main/java/io/mailtrap/exception/InvalidRequestBodyException.java b/src/main/java/io/mailtrap/exception/InvalidRequestBodyException.java index dafcb38..e2b9a06 100644 --- a/src/main/java/io/mailtrap/exception/InvalidRequestBodyException.java +++ b/src/main/java/io/mailtrap/exception/InvalidRequestBodyException.java @@ -9,4 +9,8 @@ public InvalidRequestBodyException(String errorMessage) { super(errorMessage); } + public InvalidRequestBodyException(String errorMessage, Exception cause) { + super(errorMessage, cause); + } + } diff --git a/src/main/java/io/mailtrap/model/mailvalidation/ContentView.java b/src/main/java/io/mailtrap/model/mailvalidation/ContentView.java new file mode 100644 index 0000000..0604838 --- /dev/null +++ b/src/main/java/io/mailtrap/model/mailvalidation/ContentView.java @@ -0,0 +1,21 @@ +package io.mailtrap.model.mailvalidation; + +import java.util.Map; + +/** + * An adapter used by mail content validation rules. It exposes only the fields that participate in + * subject/text/html/template logic so the same rules can run for both single and batch sends. + */ +public interface ContentView { + + String getSubject(); + + String getText(); + + String getHtml(); + + String getTemplateUuid(); + + Map getTemplateVariables(); + +} diff --git a/src/main/java/io/mailtrap/model/mailvalidation/MailContentView.java b/src/main/java/io/mailtrap/model/mailvalidation/MailContentView.java new file mode 100644 index 0000000..98f11ba --- /dev/null +++ b/src/main/java/io/mailtrap/model/mailvalidation/MailContentView.java @@ -0,0 +1,41 @@ +package io.mailtrap.model.mailvalidation; + +import io.mailtrap.model.request.emails.MailtrapMail; + +import java.util.Map; + +/** + * ContentView implementation for a single-send MailtrapMail. + */ +public final class MailContentView implements ContentView { + private final MailtrapMail mail; + + public String getSubject() { + return mail.getSubject(); + } + + public String getText() { + return mail.getText(); + } + + public String getHtml() { + return mail.getHtml(); + } + + public String getTemplateUuid() { + return mail.getTemplateUuid(); + } + + public Map getTemplateVariables() { + return mail.getTemplateVariables(); + } + + public static ContentView of(MailtrapMail content) { + return new MailContentView(content); + } + + private MailContentView(MailtrapMail content) { + this.mail = content; + } +} + diff --git a/src/main/java/io/mailtrap/model/mailvalidation/ResolvedMailContentView.java b/src/main/java/io/mailtrap/model/mailvalidation/ResolvedMailContentView.java new file mode 100644 index 0000000..7f2c407 --- /dev/null +++ b/src/main/java/io/mailtrap/model/mailvalidation/ResolvedMailContentView.java @@ -0,0 +1,39 @@ +package io.mailtrap.model.mailvalidation; + +import java.util.Map; + +/** + * ContentView implementation for a batch item via ResolvedMailView. Exposes the already-resolved (item-first, base-fallback) + * values to the shared content rules. + */ +public final class ResolvedMailContentView implements ContentView { + private final ResolvedMailView mailView; + + public String getSubject() { + return mailView.getSubject(); + } + + public String getText() { + return mailView.getText(); + } + + public String getHtml() { + return mailView.getHtml(); + } + + public String getTemplateUuid() { + return mailView.getTemplateUuid(); + } + + public Map getTemplateVariables() { + return mailView.getTemplateVariables(); + } + + public static ContentView of(ResolvedMailView mailView) { + return new ResolvedMailContentView(mailView); + } + + private ResolvedMailContentView(ResolvedMailView mailView) { + this.mailView = mailView; + } +} diff --git a/src/main/java/io/mailtrap/model/mailvalidation/ResolvedMailView.java b/src/main/java/io/mailtrap/model/mailvalidation/ResolvedMailView.java new file mode 100644 index 0000000..6c663f2 --- /dev/null +++ b/src/main/java/io/mailtrap/model/mailvalidation/ResolvedMailView.java @@ -0,0 +1,90 @@ +package io.mailtrap.model.mailvalidation; + +import io.mailtrap.model.request.emails.Address; +import io.mailtrap.model.request.emails.BatchEmailBase; +import io.mailtrap.model.request.emails.EmailAttachment; +import io.mailtrap.model.request.emails.MailtrapMail; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; +import java.util.Map; + +/** + * Read-only overlay that resolves the effective values (either from `base` or mail item) for batch request validation + */ +public final class ResolvedMailView { + + // may be null + private final BatchEmailBase base; + private final MailtrapMail item; + + public ResolvedMailView(BatchEmailBase base, MailtrapMail item) { + this.base = base; + this.item = item; + } + + @NotNull + @Valid + public Address getFrom() { + Address from = item.getFrom(); + + if (from == null && base != null) { + from = base.getFrom(); + } + + return from; + } + + public String getSubject() { + String subject = item.getSubject(); + + if (StringUtils.isBlank(subject) && base != null) { + subject = base.getSubject(); + } + + return subject; + } + + public String getText() { + String text = item.getText(); + + if (StringUtils.isBlank(text) && base != null) { + text = base.getText(); + } + + return text; + } + + public String getHtml() { + String html = item.getHtml(); + + if (StringUtils.isBlank(html) && base != null) { + html = base.getHtml(); + } + + return html; + } + + public String getTemplateUuid() { + String templateUuid = item.getTemplateUuid(); + + if (StringUtils.isBlank(templateUuid) && base != null) { + templateUuid = base.getTemplateUuid(); + } + + return templateUuid; + } + + public Map getTemplateVariables() { + Map templateVariables = item.getTemplateVariables(); + + if ((templateVariables == null || templateVariables.isEmpty()) && base != null) { + templateVariables = base.getTemplateVariables(); + } + + return templateVariables; + } +} diff --git a/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java b/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java index b08ad0a..404c5d3 100644 --- a/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java +++ b/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java @@ -4,6 +4,7 @@ import io.mailtrap.config.MailtrapConfig; import io.mailtrap.exception.InvalidRequestBodyException; import io.mailtrap.factory.MailtrapClientFactory; +import io.mailtrap.model.request.emails.BatchEmailBase; import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; import io.mailtrap.model.response.emails.BatchSendResponse; @@ -36,6 +37,14 @@ public void init() { Constants.BULK_SENDING_HOST + "/api/batch", "POST", "api/emails/batchSendRequest.json", "api/emails/batchSendResponse.json" ), + DataMock.build( + Constants.BULK_SENDING_HOST + "/api/batch", + "POST", "api/emails/batchSendWithBaseSubjectRequest.json", "api/emails/batchSendResponse.json" + ), + DataMock.build( + Constants.BULK_SENDING_HOST + "/api/batch", + "POST", "api/emails/batchSendWithBaseSubjectAndTextRequest.json", "api/emails/batchSendResponse.json" + ), DataMock.build( Constants.BULK_SENDING_HOST + "/api/batch", "POST", "api/emails/batchSendRequestFromTemplate.json", "api/emails/batchSendResponse.json" @@ -170,6 +179,48 @@ void batchSend_ValidMailFromTemplate_SuccessResponse() { assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); } + @Test + void batchSend_ValidMailWithSubjectFromBase_SuccessResponse() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder() + .base(BatchEmailBase.builder().subject("Sample valid mail subject").build()) + .requests(List.of(createValidTestMailForBatchWithNoSubject())).build(); + + // Perform call + BatchSendResponse response = bulkEmails.batchSend(batchMail); + + // Assert + assertTrue(response.isSuccess()); + assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); + } + + @Test + void batchSend_ValidMailWithSubjectAndTextFromBase_SuccessResponse() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder() + .base(BatchEmailBase.builder().subject("Sample valid mail subject").text("Sample valid mail text").build()) + .requests(List.of(createValidTestMailForBatchWithNoSubjectAndText())).build(); + + // Perform call + BatchSendResponse response = bulkEmails.batchSend(batchMail); + + // Assert + assertTrue(response.isSuccess()); + assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); + } + + @Test + void batchSend_InvalidMailWithNoSubjectAndTextNoBase_SuccessResponse() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder() + .base(BatchEmailBase.builder().text("Sample valid mail text").build()) + .requests(List.of(createValidTestMailForBatchWithNoSubjectAndText())).build(); + + // Assert + InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> bulkEmails.batchSend(batchMail)); + assertEquals(SUBJECT_MUST_NOT_BE_NULL, exception.getMessage()); + } + @Test void batchSend_NullableMail_ThrowsInvalidRequestBodyException() { // Assert diff --git a/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java b/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java index 00c7223..b9b15e9 100644 --- a/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java +++ b/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java @@ -4,6 +4,7 @@ import io.mailtrap.config.MailtrapConfig; import io.mailtrap.exception.InvalidRequestBodyException; import io.mailtrap.factory.MailtrapClientFactory; +import io.mailtrap.model.request.emails.BatchEmailBase; import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; import io.mailtrap.model.response.emails.BatchSendResponse; @@ -37,6 +38,14 @@ public void init() { Constants.EMAIL_SENDING_SEND_HOST + "/api/batch", "POST", "api/emails/batchSendRequest.json", "api/emails/batchSendResponse.json" ), + DataMock.build( + Constants.EMAIL_SENDING_SEND_HOST + "/api/batch", + "POST", "api/emails/batchSendWithBaseSubjectRequest.json", "api/emails/batchSendResponse.json" + ), + DataMock.build( + Constants.EMAIL_SENDING_SEND_HOST + "/api/batch", + "POST", "api/emails/batchSendWithBaseSubjectAndTextRequest.json", "api/emails/batchSendResponse.json" + ), DataMock.build( Constants.EMAIL_SENDING_SEND_HOST + "/api/batch", "POST", "api/emails/batchSendRequestFromTemplate.json", "api/emails/batchSendResponse.json" @@ -170,6 +179,48 @@ void batchSend_ValidMailFromTemplate_SuccessResponse() { assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); } + @Test + void batchSend_ValidMailWithSubjectFromBase_SuccessResponse() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder() + .base(BatchEmailBase.builder().subject("Sample valid mail subject").build()) + .requests(List.of(createValidTestMailForBatchWithNoSubject())).build(); + + // Perform call + BatchSendResponse response = sendApi.batchSend(batchMail); + + // Assert + assertTrue(response.isSuccess()); + assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); + } + + @Test + void batchSend_ValidMailWithSubjectAndTextFromBase_SuccessResponse() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder() + .base(BatchEmailBase.builder().subject("Sample valid mail subject").text("Sample valid mail text").build()) + .requests(List.of(createValidTestMailForBatchWithNoSubjectAndText())).build(); + + // Perform call + BatchSendResponse response = sendApi.batchSend(batchMail); + + // Assert + assertTrue(response.isSuccess()); + assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); + } + + @Test + void batchSend_InvalidMailWithNoSubjectAndTextNoBase_SuccessResponse() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder() + .base(BatchEmailBase.builder().text("Sample valid mail text").build()) + .requests(List.of(createValidTestMailForBatchWithNoSubjectAndText())).build(); + + // Assert + InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> sendApi.batchSend(batchMail)); + assertEquals(SUBJECT_MUST_NOT_BE_NULL, exception.getMessage()); + } + @Test void batchSend_NullableMail_ThrowsInvalidRequestBodyException() { // Assert diff --git a/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java b/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java index 30283b0..c395c59 100644 --- a/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java +++ b/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java @@ -4,6 +4,7 @@ import io.mailtrap.config.MailtrapConfig; import io.mailtrap.exception.InvalidRequestBodyException; import io.mailtrap.factory.MailtrapClientFactory; +import io.mailtrap.model.request.emails.BatchEmailBase; import io.mailtrap.model.request.emails.MailtrapBatchMail; import io.mailtrap.model.request.emails.MailtrapMail; import io.mailtrap.model.response.emails.BatchSendResponse; @@ -25,30 +26,38 @@ class TestingEmailsImplTest extends BaseSendTest { @BeforeEach public void init() { TestHttpClient httpClient = new TestHttpClient(List.of( - DataMock.build( - Constants.EMAIL_TESTING_SEND_HOST + "/api/send/" + INBOX_ID, - "POST", "api/emails/sendRequest.json", "api/emails/sendResponse.json" - ), - DataMock.build( - Constants.EMAIL_TESTING_SEND_HOST + "/api/send/" + INBOX_ID, - "POST", "api/emails/sendRequestFromTemplate.json", "api/emails/sendResponse.json" - ), - DataMock.build( - Constants.EMAIL_TESTING_SEND_HOST + "/api/batch/" + INBOX_ID, - "POST", "api/emails/batchSendRequest.json", "api/emails/batchSendResponse.json" - ), - DataMock.build( - Constants.EMAIL_TESTING_SEND_HOST + "/api/batch/" + INBOX_ID, - "POST", "api/emails/batchSendRequestFromTemplate.json", "api/emails/batchSendResponse.json" - ) + DataMock.build( + Constants.EMAIL_TESTING_SEND_HOST + "/api/send/" + INBOX_ID, + "POST", "api/emails/sendRequest.json", "api/emails/sendResponse.json" + ), + DataMock.build( + Constants.EMAIL_TESTING_SEND_HOST + "/api/send/" + INBOX_ID, + "POST", "api/emails/sendRequestFromTemplate.json", "api/emails/sendResponse.json" + ), + DataMock.build( + Constants.EMAIL_TESTING_SEND_HOST + "/api/batch/" + INBOX_ID, + "POST", "api/emails/batchSendRequest.json", "api/emails/batchSendResponse.json" + ), + DataMock.build( + Constants.EMAIL_TESTING_SEND_HOST + "/api/batch/" + INBOX_ID, + "POST", "api/emails/batchSendWithBaseSubjectRequest.json", "api/emails/batchSendResponse.json" + ), + DataMock.build( + Constants.EMAIL_TESTING_SEND_HOST + "/api/batch/" + INBOX_ID, + "POST", "api/emails/batchSendWithBaseSubjectAndTextRequest.json", "api/emails/batchSendResponse.json" + ), + DataMock.build( + Constants.EMAIL_TESTING_SEND_HOST + "/api/batch/" + INBOX_ID, + "POST", "api/emails/batchSendRequestFromTemplate.json", "api/emails/batchSendResponse.json" + ) )); MailtrapConfig testConfig = new MailtrapConfig.Builder() - .httpClient(httpClient) - .token("dummy_token") - .sandbox(true) - .inboxId(INBOX_ID) - .build(); + .httpClient(httpClient) + .token("dummy_token") + .sandbox(true) + .inboxId(INBOX_ID) + .build(); testingApi = MailtrapClientFactory.createMailtrapClient(testConfig).testingApi().emails(); } @@ -172,6 +181,48 @@ void batchSend_ValidMailFromTemplate_SuccessResponse() { assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); } + @Test + void batchSend_ValidMailWithSubjectFromBase_SuccessResponse() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder() + .base(BatchEmailBase.builder().subject("Sample valid mail subject").build()) + .requests(List.of(createValidTestMailForBatchWithNoSubject())).build(); + + // Perform call + BatchSendResponse response = testingApi.batchSend(batchMail, INBOX_ID); + + // Assert + assertTrue(response.isSuccess()); + assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); + } + + @Test + void batchSend_ValidMailWithSubjectAndTextFromBase_SuccessResponse() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder() + .base(BatchEmailBase.builder().subject("Sample valid mail subject").text("Sample valid mail text").build()) + .requests(List.of(createValidTestMailForBatchWithNoSubjectAndText())).build(); + + // Perform call + BatchSendResponse response = testingApi.batchSend(batchMail, INBOX_ID); + + // Assert + assertTrue(response.isSuccess()); + assertEquals("22222", response.getResponses().get(0).getMessageIds().get(0)); + } + + @Test + void batchSend_InvalidMailWithNoSubjectAndTextNoBase_SuccessResponse() { + // Set up test data + MailtrapBatchMail batchMail = MailtrapBatchMail.builder() + .base(BatchEmailBase.builder().text("Sample valid mail text").build()) + .requests(List.of(createValidTestMailForBatchWithNoSubjectAndText())).build(); + + // Assert + InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> testingApi.batchSend(batchMail, INBOX_ID)); + assertEquals(SUBJECT_MUST_NOT_BE_NULL, exception.getMessage()); + } + @Test void batchSend_NullableMail_ThrowsInvalidRequestBodyException() { // Assert diff --git a/src/test/java/io/mailtrap/testutils/BaseSendTest.java b/src/test/java/io/mailtrap/testutils/BaseSendTest.java index 0114a38..2a7eeae 100644 --- a/src/test/java/io/mailtrap/testutils/BaseSendTest.java +++ b/src/test/java/io/mailtrap/testutils/BaseSendTest.java @@ -20,6 +20,7 @@ public class BaseSendTest { protected final String MAIL_MUST_HAVE_SUBJECT_AND_EITHER_TEXT_OR_HTML = "Mail must have subject and either text or html when templateUuid is not provided"; protected final String MAIL_MUST_NOT_BE_NULL = "Mail must not be null"; protected final String BATCH_MAIL_MUST_NOT_BE_NULL = "BatchMail must not be null"; + protected final String SUBJECT_MUST_NOT_BE_NULL = "Subject must not be null or empty"; private Address getAddress(String email, String name) { return new Address(email, name); @@ -48,6 +49,32 @@ protected MailtrapMail createValidTestMail() { .build(); } + protected MailtrapMail createValidTestMailForBatchWithNoSubject() { + Address from = getAddress("sender@example.com", "John Doe"); + Address to = getAddress("receiver@example.com", "Jane Doe"); + EmailAttachment attachment = getAttachment(); + + return MailtrapMail.builder() + .from(from) + .to(List.of(to)) + .text("Sample valid mail text") + .html("Test HTML") + .attachments(List.of(attachment)) + .build(); + } + + protected MailtrapMail createValidTestMailForBatchWithNoSubjectAndText() { + Address from = getAddress("sender@example.com", "John Doe"); + Address to = getAddress("receiver@example.com", "Jane Doe"); + EmailAttachment attachment = getAttachment(); + + return MailtrapMail.builder() + .from(from) + .to(List.of(to)) + .attachments(List.of(attachment)) + .build(); + } + protected MailtrapMail createInvalidTestMail() { Address from = getAddress("", "John Doe"); Address to = getAddress("receiver@example.com", null); diff --git a/src/test/resources/api/emails/batchSendWithBaseSubjectAndTextRequest.json b/src/test/resources/api/emails/batchSendWithBaseSubjectAndTextRequest.json new file mode 100644 index 0000000..64a1c49 --- /dev/null +++ b/src/test/resources/api/emails/batchSendWithBaseSubjectAndTextRequest.json @@ -0,0 +1,27 @@ +{ + "base": { + "subject": "Sample valid mail subject", + "text": "Sample valid mail text" + }, + "requests": [ + { + "from": { + "name": "John Doe", + "email": "sender@example.com" + }, + "to": [ + { + "name": "Jane Doe", + "email": "receiver@example.com" + } + ], + "attachments": [ + { + "content": "c2FtcGxlIHRleHQgaW4gdGV4dCBmaWxl", + "type": "text/plain", + "filename": "attachment.txt" + } + ] + } + ] +} diff --git a/src/test/resources/api/emails/batchSendWithBaseSubjectRequest.json b/src/test/resources/api/emails/batchSendWithBaseSubjectRequest.json new file mode 100644 index 0000000..a6a802a --- /dev/null +++ b/src/test/resources/api/emails/batchSendWithBaseSubjectRequest.json @@ -0,0 +1,28 @@ +{ + "base": { + "subject": "Sample valid mail subject" + }, + "requests": [ + { + "from": { + "name": "John Doe", + "email": "sender@example.com" + }, + "to": [ + { + "name": "Jane Doe", + "email": "receiver@example.com" + } + ], + "attachments": [ + { + "content": "c2FtcGxlIHRleHQgaW4gdGV4dCBmaWxl", + "type": "text/plain", + "filename": "attachment.txt" + } + ], + "text": "Sample valid mail text", + "html": "Test HTML" + } + ] +} From f4a978b4623ce7e5c75c30bfc37fc796ba24c97e Mon Sep 17 00:00:00 2001 From: vtasun Date: Sat, 13 Sep 2025 02:09:18 +0300 Subject: [PATCH 4/5] Minor updates --- .../java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java | 6 +++--- .../mailtrap/api/sendingemails/SendingEmailsImplTest.java | 6 +++--- .../mailtrap/api/testingemails/TestingEmailsImplTest.java | 6 +++--- src/test/java/io/mailtrap/testutils/BaseSendTest.java | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java b/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java index 404c5d3..453b40e 100644 --- a/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java +++ b/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java @@ -199,7 +199,7 @@ void batchSend_ValidMailWithSubjectAndTextFromBase_SuccessResponse() { // Set up test data MailtrapBatchMail batchMail = MailtrapBatchMail.builder() .base(BatchEmailBase.builder().subject("Sample valid mail subject").text("Sample valid mail text").build()) - .requests(List.of(createValidTestMailForBatchWithNoSubjectAndText())).build(); + .requests(List.of(createTestMailForBatchWithNoSubjectAndText())).build(); // Perform call BatchSendResponse response = bulkEmails.batchSend(batchMail); @@ -210,11 +210,11 @@ void batchSend_ValidMailWithSubjectAndTextFromBase_SuccessResponse() { } @Test - void batchSend_InvalidMailWithNoSubjectAndTextNoBase_SuccessResponse() { + void batchSend_InvalidMailWithNoSubjectAndTextNoBase_ThrowsInvalidRequestBodyException() { // Set up test data MailtrapBatchMail batchMail = MailtrapBatchMail.builder() .base(BatchEmailBase.builder().text("Sample valid mail text").build()) - .requests(List.of(createValidTestMailForBatchWithNoSubjectAndText())).build(); + .requests(List.of(createTestMailForBatchWithNoSubjectAndText())).build(); // Assert InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> bulkEmails.batchSend(batchMail)); diff --git a/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java b/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java index b9b15e9..39394e1 100644 --- a/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java +++ b/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java @@ -199,7 +199,7 @@ void batchSend_ValidMailWithSubjectAndTextFromBase_SuccessResponse() { // Set up test data MailtrapBatchMail batchMail = MailtrapBatchMail.builder() .base(BatchEmailBase.builder().subject("Sample valid mail subject").text("Sample valid mail text").build()) - .requests(List.of(createValidTestMailForBatchWithNoSubjectAndText())).build(); + .requests(List.of(createTestMailForBatchWithNoSubjectAndText())).build(); // Perform call BatchSendResponse response = sendApi.batchSend(batchMail); @@ -210,11 +210,11 @@ void batchSend_ValidMailWithSubjectAndTextFromBase_SuccessResponse() { } @Test - void batchSend_InvalidMailWithNoSubjectAndTextNoBase_SuccessResponse() { + void batchSend_InvalidMailWithNoSubjectAndTextNoBase_ThrowsInvalidRequestBodyException() { // Set up test data MailtrapBatchMail batchMail = MailtrapBatchMail.builder() .base(BatchEmailBase.builder().text("Sample valid mail text").build()) - .requests(List.of(createValidTestMailForBatchWithNoSubjectAndText())).build(); + .requests(List.of(createTestMailForBatchWithNoSubjectAndText())).build(); // Assert InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> sendApi.batchSend(batchMail)); diff --git a/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java b/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java index c395c59..57d45bb 100644 --- a/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java +++ b/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java @@ -201,7 +201,7 @@ void batchSend_ValidMailWithSubjectAndTextFromBase_SuccessResponse() { // Set up test data MailtrapBatchMail batchMail = MailtrapBatchMail.builder() .base(BatchEmailBase.builder().subject("Sample valid mail subject").text("Sample valid mail text").build()) - .requests(List.of(createValidTestMailForBatchWithNoSubjectAndText())).build(); + .requests(List.of(createTestMailForBatchWithNoSubjectAndText())).build(); // Perform call BatchSendResponse response = testingApi.batchSend(batchMail, INBOX_ID); @@ -212,11 +212,11 @@ void batchSend_ValidMailWithSubjectAndTextFromBase_SuccessResponse() { } @Test - void batchSend_InvalidMailWithNoSubjectAndTextNoBase_SuccessResponse() { + void batchSend_InvalidMailWithNoSubjectAndTextNoBase_ThrowsInvalidRequestBodyException() { // Set up test data MailtrapBatchMail batchMail = MailtrapBatchMail.builder() .base(BatchEmailBase.builder().text("Sample valid mail text").build()) - .requests(List.of(createValidTestMailForBatchWithNoSubjectAndText())).build(); + .requests(List.of(createTestMailForBatchWithNoSubjectAndText())).build(); // Assert InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> testingApi.batchSend(batchMail, INBOX_ID)); diff --git a/src/test/java/io/mailtrap/testutils/BaseSendTest.java b/src/test/java/io/mailtrap/testutils/BaseSendTest.java index 2a7eeae..c7108e9 100644 --- a/src/test/java/io/mailtrap/testutils/BaseSendTest.java +++ b/src/test/java/io/mailtrap/testutils/BaseSendTest.java @@ -63,7 +63,7 @@ protected MailtrapMail createValidTestMailForBatchWithNoSubject() { .build(); } - protected MailtrapMail createValidTestMailForBatchWithNoSubjectAndText() { + protected MailtrapMail createTestMailForBatchWithNoSubjectAndText() { Address from = getAddress("sender@example.com", "John Doe"); Address to = getAddress("receiver@example.com", "Jane Doe"); EmailAttachment attachment = getAttachment(); From 5ec932932278cbdffdb24a543d05398eacab7e8a Mon Sep 17 00:00:00 2001 From: vtasun Date: Sat, 13 Sep 2025 02:14:31 +0300 Subject: [PATCH 5/5] Removed duplicating constant --- .../java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java | 2 +- .../io/mailtrap/api/sendingemails/SendingEmailsImplTest.java | 2 +- .../io/mailtrap/api/testingemails/TestingEmailsImplTest.java | 2 +- src/test/java/io/mailtrap/testutils/BaseSendTest.java | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java b/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java index 453b40e..c0844fb 100644 --- a/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java +++ b/src/test/java/io/mailtrap/api/bulkemails/BulkEmailsImplTest.java @@ -77,7 +77,7 @@ void send_MailWithoutTemplateUuidAndTextAndHtml_ThrowsInvalidRequestBodyExceptio // Assert InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> bulkEmails.send(mail)); - assertEquals(TEMPLATE_UUID_OR_SUBJECT_AND_TEXT_OR_HTML_MUST_NOT_BE_EMPTY, exception.getMessage()); + assertEquals(MAIL_MUST_HAVE_SUBJECT_AND_EITHER_TEXT_OR_HTML, exception.getMessage()); } @Test diff --git a/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java b/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java index 39394e1..b2cf4b0 100644 --- a/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java +++ b/src/test/java/io/mailtrap/api/sendingemails/SendingEmailsImplTest.java @@ -77,7 +77,7 @@ void send_MailWithoutTemplateUuidAndTextAndHtml_ThrowsInvalidRequestBodyExceptio // Assert InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> sendApi.send(mail)); - assertEquals(TEMPLATE_UUID_OR_SUBJECT_AND_TEXT_OR_HTML_MUST_NOT_BE_EMPTY, exception.getMessage()); + assertEquals(MAIL_MUST_HAVE_SUBJECT_AND_EITHER_TEXT_OR_HTML, exception.getMessage()); } @Test diff --git a/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java b/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java index 57d45bb..ac70b31 100644 --- a/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java +++ b/src/test/java/io/mailtrap/api/testingemails/TestingEmailsImplTest.java @@ -79,7 +79,7 @@ void send_MailWithoutTemplateUuidAndTextAndHtml_ThrowsInvalidRequestBodyExceptio // Assert InvalidRequestBodyException exception = assertThrows(InvalidRequestBodyException.class, () -> testingApi.send(mail, INBOX_ID)); - assertEquals(TEMPLATE_UUID_OR_SUBJECT_AND_TEXT_OR_HTML_MUST_NOT_BE_EMPTY, exception.getMessage()); + assertEquals(MAIL_MUST_HAVE_SUBJECT_AND_EITHER_TEXT_OR_HTML, exception.getMessage()); } @Test diff --git a/src/test/java/io/mailtrap/testutils/BaseSendTest.java b/src/test/java/io/mailtrap/testutils/BaseSendTest.java index c7108e9..a2e0797 100644 --- a/src/test/java/io/mailtrap/testutils/BaseSendTest.java +++ b/src/test/java/io/mailtrap/testutils/BaseSendTest.java @@ -14,7 +14,6 @@ public class BaseSendTest { protected final String BULK_AND_SANDBOX_TRUE_IN_SENDING_CONFIG = "Bulk mode is not applicable for Testing API"; protected final String INBOX_ID_REQUIRED = "Testing API requires inbox ID"; protected final String INVALID_REQUEST_EMPTY_BODY_FROM_EMAIL = "Invalid request body. Violations: from.email=must not be empty"; - protected final String TEMPLATE_UUID_OR_SUBJECT_AND_TEXT_OR_HTML_MUST_NOT_BE_EMPTY = "Mail must have subject and either text or html when templateUuid is not provided"; protected final String TEMPLATE_UUID_IS_USED_SUBJECT_AND_TEXT_AND_HTML_SHOULD_BE_EMPTY = "When templateUuid is used, subject, text, and html must not be used"; protected final String TEMPLATE_VARIABLES_SHOULD_BE_USED_WITH_TEMPLATE_UUID = "Mail templateVariables must only be used with templateUuid"; protected final String MAIL_MUST_HAVE_SUBJECT_AND_EITHER_TEXT_OR_HTML = "Mail must have subject and either text or html when templateUuid is not provided";