Skip to content

Commit 4d5554e

Browse files
author
Viktor Zahorodnii
authored
Merge pull request #38 from railsware/feature/batch-send
Implement `/batch` method for sending/testing/bulk emails
2 parents 7841c8c + 5ec9329 commit 4d5554e

30 files changed

+1214
-90
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package io.mailtrap.examples.bulk;
2+
3+
import io.mailtrap.config.MailtrapConfig;
4+
import io.mailtrap.factory.MailtrapClientFactory;
5+
import io.mailtrap.model.request.emails.Address;
6+
import io.mailtrap.model.request.emails.MailtrapBatchMail;
7+
import io.mailtrap.model.request.emails.BatchEmailBase;
8+
import io.mailtrap.model.request.emails.MailtrapMail;
9+
10+
import java.util.List;
11+
import java.util.Map;
12+
13+
public class Batch {
14+
15+
private static final String TOKEN = "<YOUR MAILTRAP TOKEN>";
16+
private static final String SENDER_EMAIL = "[email protected]";
17+
private static final String RECIPIENT_EMAIL = "[email protected]";
18+
19+
public static void main(String[] args) {
20+
final var config = new MailtrapConfig.Builder()
21+
.token(TOKEN)
22+
.build();
23+
24+
final var client = MailtrapClientFactory.createMailtrapClient(config);
25+
26+
final var mail = MailtrapMail.builder()
27+
.from(new Address(SENDER_EMAIL))
28+
.to(List.of(new Address(RECIPIENT_EMAIL)))
29+
.subject("Hello from Mailtrap!")
30+
.text("Welcome to Mailtrap Bulk Sending!")
31+
.build();
32+
33+
final var batchMail = MailtrapBatchMail.builder()
34+
// Optionally you can add this `base` object - if you have some common data across emails
35+
// Each property can be overridden in `requests` for individual emails
36+
.base(BatchEmailBase.builder().subject("Base Subject for all emails").build())
37+
.requests(List.of(mail))
38+
.build();
39+
40+
System.out.println(client.bulkSendingApi().emails().batchSend(batchMail));
41+
}
42+
43+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package io.mailtrap.examples.sending;
2+
3+
import io.mailtrap.config.MailtrapConfig;
4+
import io.mailtrap.factory.MailtrapClientFactory;
5+
import io.mailtrap.model.request.emails.Address;
6+
import io.mailtrap.model.request.emails.MailtrapBatchMail;
7+
import io.mailtrap.model.request.emails.BatchEmailBase;
8+
import io.mailtrap.model.request.emails.MailtrapMail;
9+
10+
import java.util.List;
11+
import java.util.Map;
12+
13+
public class Batch {
14+
15+
private static final String TOKEN = "<YOUR MAILTRAP TOKEN>";
16+
private static final String SENDER_EMAIL = "[email protected]";
17+
private static final String RECIPIENT_EMAIL = "[email protected]";
18+
19+
public static void main(String[] args) {
20+
final var config = new MailtrapConfig.Builder()
21+
.token(TOKEN)
22+
.build();
23+
24+
final var client = MailtrapClientFactory.createMailtrapClient(config);
25+
26+
final var mail = MailtrapMail.builder()
27+
.from(new Address(SENDER_EMAIL))
28+
.to(List.of(new Address(RECIPIENT_EMAIL)))
29+
.subject("Hello from Mailtrap Sending!")
30+
.text("Welcome to Mailtrap Sending!")
31+
.build();
32+
33+
final var batchMail = MailtrapBatchMail.builder()
34+
// Optionally you can add this `base` object - if you have some common data across emails
35+
// Each property can be overridden in `requests` for individual emails
36+
.base(BatchEmailBase.builder().subject("Base Subject for all emails").build())
37+
.requests(List.of(mail))
38+
.build();
39+
40+
System.out.println(client.sendingApi().emails().batchSend(batchMail));
41+
}
42+
43+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package io.mailtrap.examples.testing;
2+
3+
import io.mailtrap.config.MailtrapConfig;
4+
import io.mailtrap.factory.MailtrapClientFactory;
5+
import io.mailtrap.model.request.emails.Address;
6+
import io.mailtrap.model.request.emails.MailtrapBatchMail;
7+
import io.mailtrap.model.request.emails.BatchEmailBase;
8+
import io.mailtrap.model.request.emails.MailtrapMail;
9+
10+
import java.util.List;
11+
import java.util.Map;
12+
13+
public class Batch {
14+
15+
private static final String TOKEN = "<YOUR MAILTRAP TOKEN>";
16+
private static final String SENDER_EMAIL = "[email protected]";
17+
private static final String RECIPIENT_EMAIL = "[email protected]";
18+
private static final long INBOX_ID = 1337L;
19+
20+
public static void main(String[] args) {
21+
final var config = new MailtrapConfig.Builder()
22+
.token(TOKEN)
23+
.inboxId(INBOX_ID)
24+
.build();
25+
26+
final var client = MailtrapClientFactory.createMailtrapClient(config);
27+
28+
final var mail = MailtrapMail.builder()
29+
.from(new Address("John Doe", SENDER_EMAIL))
30+
.to(List.of(new Address("Jane Doe", RECIPIENT_EMAIL)))
31+
.templateUuid("813t39es-t74i-4308-b037-0n6bg8b1fe88")
32+
.templateVariables(Map.of(
33+
"user_name", "Jack Sparrow",
34+
"testing_template", "true"
35+
))
36+
.build();
37+
38+
final var batchMail = MailtrapBatchMail.builder()
39+
// Optionally you can add this `base` object - if you have some common data across emails
40+
// Each property can be overridden in `requests` for individual emails
41+
.base(BatchEmailBase.builder().templateUuid("base-template-uuid").build())
42+
.requests(List.of(mail))
43+
.build();
44+
45+
System.out.println(client.testingApi().emails().batchSend(batchMail, config.getInboxId()));
46+
}
47+
48+
}

src/main/java/io/mailtrap/api/apiresource/SendApiResource.java

Lines changed: 76 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,18 @@
33
import io.mailtrap.CustomValidator;
44
import io.mailtrap.config.MailtrapConfig;
55
import io.mailtrap.exception.InvalidRequestBodyException;
6+
import io.mailtrap.model.mailvalidation.ContentView;
7+
import io.mailtrap.model.mailvalidation.MailContentView;
8+
import io.mailtrap.model.mailvalidation.ResolvedMailContentView;
9+
import io.mailtrap.model.mailvalidation.ResolvedMailView;
10+
import io.mailtrap.model.request.emails.BatchEmailBase;
11+
import io.mailtrap.model.request.emails.MailtrapBatchMail;
612
import io.mailtrap.model.request.emails.MailtrapMail;
713
import org.apache.commons.collections4.MapUtils;
814
import org.apache.commons.lang3.StringUtils;
915

16+
import java.util.Objects;
17+
1018
/**
1119
* Abstract class representing a resource for sending emails via Mailtrap API.
1220
*/
@@ -22,51 +30,87 @@ protected SendApiResource(MailtrapConfig config, CustomValidator customValidator
2230
* @param mail The email message to be validated.
2331
* @throws InvalidRequestBodyException If the request body is invalid.
2432
*/
25-
protected void validateRequestBodyOrThrowException(MailtrapMail mail) throws InvalidRequestBodyException {
26-
// Check if the mail object itself is null
33+
protected void validateMailPayload(MailtrapMail mail) {
2734
if (mail == null) {
2835
throw new InvalidRequestBodyException("Mail must not be null");
2936
}
3037

31-
// Check if all three subject, text, and html are empty
32-
boolean isSubjectTextHtmlEmpty = StringUtils.isEmpty(mail.getSubject())
33-
&& StringUtils.isEmpty(mail.getText())
34-
&& StringUtils.isEmpty(mail.getHtml());
35-
36-
// Validate depending on whether the templateUuid is set
37-
if (StringUtils.isEmpty(mail.getTemplateUuid())) {
38-
// Validation for the scenario where templateUuid is not provided
39-
validateWithoutTemplate(mail, isSubjectTextHtmlEmpty);
40-
} else {
41-
// Validation for the scenario where templateUuid is provided
42-
validateWithTemplate(mail);
43-
}
44-
45-
// Additional validation logic (assumed to be provided by the user)
38+
// Perform bean validation (NotNull, etc.)
4639
validateRequestBodyAndThrowException(mail);
40+
41+
// Validate subject/text/html/templateUuid
42+
validateContentRules(MailContentView.of(mail));
4743
}
4844

49-
private void validateWithoutTemplate(MailtrapMail mail, boolean isSubjectTextHtmlEmpty) throws InvalidRequestBodyException {
50-
// Ensure that at least subject, text, or html is provided if templateUuid is not set
51-
if (isSubjectTextHtmlEmpty) {
52-
throw new InvalidRequestBodyException("Mail must have subject and either text or html when templateUuid is not provided");
53-
}
45+
/**
46+
* Validates the request body of batch email and throws an exception if it is invalid.
47+
*
48+
* @param batch batch request to be validated.
49+
* @throws InvalidRequestBodyException If the request body is invalid.
50+
*/
51+
protected void validateBatchPayload(MailtrapBatchMail batch) {
52+
assertBatchMailNotNull(batch);
53+
54+
BatchEmailBase base = batch.getBase();
5455

55-
// Ensure templateVariables are not used if templateUuid is not set
56-
if (MapUtils.isNotEmpty(mail.getTemplateVariables())) {
57-
throw new InvalidRequestBodyException("Mail templateVariables must only be used with templateUuid");
56+
for (int i = 0; i < batch.getRequests().size(); i++) {
57+
MailtrapMail mail = batch.getRequests().get(i);
58+
ResolvedMailView mailView = new ResolvedMailView(base, mail);
59+
60+
try {
61+
// Perform bean validation (NotNull, etc.)
62+
validateRequestBodyAndThrowException(mailView);
63+
} catch (InvalidRequestBodyException e) {
64+
throw new InvalidRequestBodyException("requests[" + i + "]: " + e.getMessage(), e);
65+
}
66+
67+
validateContentRules(ResolvedMailContentView.of(mailView));
68+
69+
if (mailView.getFrom() == null) {
70+
throw new InvalidRequestBodyException("requests[" + i + "]: from is required (either in mail or base)");
71+
}
5872
}
73+
}
5974

60-
// Ensure the subject is not empty
61-
if (StringUtils.isEmpty(mail.getSubject())) {
62-
throw new InvalidRequestBodyException("Subject must not be null or empty");
75+
private void assertBatchMailNotNull(MailtrapBatchMail batchMail) {
76+
if (batchMail == null) {
77+
throw new InvalidRequestBodyException("BatchMail must not be null");
78+
}
79+
if (batchMail.getRequests() == null || batchMail.getRequests().isEmpty()) {
80+
throw new InvalidRequestBodyException("BatchMail.requests must not be null or empty");
81+
}
82+
if (batchMail.getRequests().stream().anyMatch(Objects::isNull)) {
83+
throw new InvalidRequestBodyException("BatchMail.requests must not contain null items");
6384
}
85+
6486
}
6587

66-
private void validateWithTemplate(MailtrapMail mail) throws InvalidRequestBodyException {
67-
// Ensure that subject, text, and html are not used when templateUuid is set
68-
if (StringUtils.isNotEmpty(mail.getText()) || StringUtils.isNotEmpty(mail.getHtml()) || StringUtils.isNotEmpty(mail.getSubject())) {
69-
throw new InvalidRequestBodyException("When templateUuid is used, subject, text, and html must not be used");
88+
private void validateContentRules(ContentView v) {
89+
boolean templateUuidBlank = StringUtils.isBlank(v.getTemplateUuid());
90+
91+
boolean subjectTextHtmlEmpty = StringUtils.isBlank(v.getSubject())
92+
&& StringUtils.isBlank(v.getText())
93+
&& StringUtils.isBlank(v.getHtml());
94+
95+
if (templateUuidBlank) {
96+
if (subjectTextHtmlEmpty) {
97+
throw new InvalidRequestBodyException("Mail must have subject and either text or html when templateUuid is not provided");
98+
}
99+
if (MapUtils.isNotEmpty(v.getTemplateVariables())) {
100+
throw new InvalidRequestBodyException("Mail templateVariables must only be used with templateUuid");
101+
}
102+
if (StringUtils.isBlank(v.getSubject())) {
103+
throw new InvalidRequestBodyException("Subject must not be null or empty");
104+
}
105+
if (StringUtils.isBlank(v.getText()) && StringUtils.isBlank(v.getHtml())) {
106+
throw new InvalidRequestBodyException("Mail must have subject and either text or html when templateUuid is not provided");
107+
}
108+
} else {
109+
if (StringUtils.isNotEmpty(v.getSubject())
110+
|| StringUtils.isNotEmpty(v.getText())
111+
|| StringUtils.isNotEmpty(v.getHtml()))
112+
throw new InvalidRequestBodyException("When templateUuid is used, subject, text, and html must not be used");
70113
}
71114
}
115+
72116
}

src/main/java/io/mailtrap/api/bulkemails/BulkEmails.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import io.mailtrap.exception.InvalidRequestBodyException;
44
import io.mailtrap.exception.http.HttpException;
5+
import io.mailtrap.model.request.emails.MailtrapBatchMail;
56
import io.mailtrap.model.request.emails.MailtrapMail;
7+
import io.mailtrap.model.response.emails.BatchSendResponse;
68
import io.mailtrap.model.response.emails.SendResponse;
79

810
/**
@@ -20,4 +22,6 @@ public interface BulkEmails {
2022
* @throws InvalidRequestBodyException If the request body is invalid.
2123
*/
2224
SendResponse send(MailtrapMail mail) throws HttpException, InvalidRequestBodyException;
25+
26+
BatchSendResponse batchSend(MailtrapBatchMail mail) throws HttpException, InvalidRequestBodyException;
2327
}

src/main/java/io/mailtrap/api/bulkemails/BulkEmailsImpl.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@
44
import io.mailtrap.CustomValidator;
55
import io.mailtrap.api.apiresource.SendApiResource;
66
import io.mailtrap.config.MailtrapConfig;
7+
import io.mailtrap.exception.InvalidRequestBodyException;
8+
import io.mailtrap.exception.http.HttpException;
79
import io.mailtrap.http.RequestData;
10+
import io.mailtrap.model.request.emails.MailtrapBatchMail;
811
import io.mailtrap.model.request.emails.MailtrapMail;
12+
import io.mailtrap.model.response.emails.BatchSendResponse;
913
import io.mailtrap.model.response.emails.SendResponse;
1014

1115
/**
@@ -20,11 +24,20 @@ public BulkEmailsImpl(MailtrapConfig config, CustomValidator customValidator) {
2024

2125
@Override
2226
public SendResponse send(MailtrapMail mail) {
23-
validateRequestBodyOrThrowException(mail);
27+
validateMailPayload(mail);
2428
RequestData requestData = new RequestData();
2529
if (mail.getHeaders() != null) {
2630
requestData.setHeaders(mail.getHeaders());
2731
}
2832
return httpClient.post(apiHost + "/api/send", mail, requestData, SendResponse.class);
2933
}
34+
35+
@Override
36+
public BatchSendResponse batchSend(MailtrapBatchMail mail) throws HttpException, InvalidRequestBodyException {
37+
validateBatchPayload(mail);
38+
39+
return
40+
httpClient.post(apiHost + "/api/batch", mail, new RequestData(), BatchSendResponse.class);
41+
42+
}
3043
}

src/main/java/io/mailtrap/api/sendingemails/SendingEmails.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import io.mailtrap.exception.InvalidRequestBodyException;
44
import io.mailtrap.exception.http.HttpException;
5+
import io.mailtrap.model.request.emails.MailtrapBatchMail;
56
import io.mailtrap.model.request.emails.MailtrapMail;
7+
import io.mailtrap.model.response.emails.BatchSendResponse;
68
import io.mailtrap.model.response.emails.SendResponse;
79

810
/**
@@ -20,4 +22,6 @@ public interface SendingEmails {
2022
* @throws InvalidRequestBodyException If the request body is invalid.
2123
*/
2224
SendResponse send(MailtrapMail mail) throws HttpException, InvalidRequestBodyException;
25+
26+
BatchSendResponse batchSend(MailtrapBatchMail mail) throws HttpException, InvalidRequestBodyException;
2327
}

src/main/java/io/mailtrap/api/sendingemails/SendingEmailsImpl.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@
44
import io.mailtrap.CustomValidator;
55
import io.mailtrap.api.apiresource.SendApiResource;
66
import io.mailtrap.config.MailtrapConfig;
7+
import io.mailtrap.exception.InvalidRequestBodyException;
8+
import io.mailtrap.exception.http.HttpException;
79
import io.mailtrap.http.RequestData;
10+
import io.mailtrap.model.request.emails.MailtrapBatchMail;
811
import io.mailtrap.model.request.emails.MailtrapMail;
12+
import io.mailtrap.model.response.emails.BatchSendResponse;
913
import io.mailtrap.model.response.emails.SendResponse;
1014

1115
/**
@@ -20,12 +24,20 @@ public SendingEmailsImpl(MailtrapConfig config, CustomValidator customValidator)
2024

2125
@Override
2226
public SendResponse send(MailtrapMail mail) {
23-
validateRequestBodyOrThrowException(mail);
27+
validateMailPayload(mail);
2428
RequestData requestData = new RequestData();
2529
if (mail.getHeaders() != null) {
2630
requestData.setHeaders(mail.getHeaders());
2731
}
2832
return httpClient.post(apiHost + "/api/send", mail, requestData, SendResponse.class);
2933
}
3034

35+
@Override
36+
public BatchSendResponse batchSend(MailtrapBatchMail mail) throws HttpException, InvalidRequestBodyException {
37+
validateBatchPayload(mail);
38+
39+
return
40+
httpClient.post(apiHost + "/api/batch", mail, new RequestData(), BatchSendResponse.class);
41+
}
42+
3143
}

src/main/java/io/mailtrap/api/testingemails/TestingEmails.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import io.mailtrap.exception.InvalidRequestBodyException;
44
import io.mailtrap.exception.http.HttpException;
5+
import io.mailtrap.model.request.emails.MailtrapBatchMail;
56
import io.mailtrap.model.request.emails.MailtrapMail;
7+
import io.mailtrap.model.response.emails.BatchSendResponse;
68
import io.mailtrap.model.response.emails.SendResponse;
79

810
/**
@@ -21,4 +23,6 @@ public interface TestingEmails {
2123
* @throws InvalidRequestBodyException If the request body is invalid.
2224
*/
2325
SendResponse send(MailtrapMail mail, long inboxId) throws HttpException, InvalidRequestBodyException;
26+
27+
BatchSendResponse batchSend(MailtrapBatchMail mail, long inboxId) throws HttpException, InvalidRequestBodyException;
2428
}

0 commit comments

Comments
 (0)