diff --git a/examples/java/io/mailtrap/examples/suppressions/Suppressions.java b/examples/java/io/mailtrap/examples/suppressions/Suppressions.java new file mode 100644 index 0000000..f1db2d0 --- /dev/null +++ b/examples/java/io/mailtrap/examples/suppressions/Suppressions.java @@ -0,0 +1,31 @@ +package io.mailtrap.examples.suppressions; + +import io.mailtrap.config.MailtrapConfig; +import io.mailtrap.factory.MailtrapClientFactory; + +public class Suppressions { + + private static final String TOKEN = ""; + private static final long ACCOUNT_ID = 1L; + private static final String EMAIL = "example@mailtrap.io"; + + public static void main(String[] args) { + final var config = new MailtrapConfig.Builder() + .token(TOKEN) + .build(); + + final var client = MailtrapClientFactory.createMailtrapClient(config); + + var searchResponse = client.sendingApi().suppressions() + .search(ACCOUNT_ID, EMAIL); + + System.out.println(searchResponse); + + if (!searchResponse.isEmpty()) { + var deletedSuppression = client.sendingApi().suppressions() + .deleteSuppression(ACCOUNT_ID, searchResponse.get(0).getId()); + + System.out.println(deletedSuppression); + } + } +} diff --git a/src/main/java/io/mailtrap/api/suppressions/Suppressions.java b/src/main/java/io/mailtrap/api/suppressions/Suppressions.java new file mode 100644 index 0000000..bccd3d2 --- /dev/null +++ b/src/main/java/io/mailtrap/api/suppressions/Suppressions.java @@ -0,0 +1,27 @@ +package io.mailtrap.api.suppressions; + +import io.mailtrap.model.response.suppressions.SuppressionsResponse; + +import java.util.List; + +public interface Suppressions { + + /** + * List and search suppressions by email. The endpoint returns up to 1000 suppressions per request. + * + * @param accountId - unique account ID + * @param email - search suppressions for this email + * @return a list of suppressions + */ + List search(long accountId, String email); + + /** + * Delete a suppression by ID. Mailtrap will no longer prevent sending to this email unless it's recorded in suppressions again. + * + * @param accountId - unique account ID + * @param suppressionId - unique suppression ID + * @return the attributes of the deleted suppression + */ + SuppressionsResponse deleteSuppression(long accountId, String suppressionId); + +} diff --git a/src/main/java/io/mailtrap/api/suppressions/SuppressionsImpl.java b/src/main/java/io/mailtrap/api/suppressions/SuppressionsImpl.java new file mode 100644 index 0000000..451ae1f --- /dev/null +++ b/src/main/java/io/mailtrap/api/suppressions/SuppressionsImpl.java @@ -0,0 +1,44 @@ +package io.mailtrap.api.suppressions; + +import io.mailtrap.Constants; +import io.mailtrap.api.apiresource.ApiResource; +import io.mailtrap.config.MailtrapConfig; +import io.mailtrap.http.RequestData; +import io.mailtrap.model.response.suppressions.SuppressionsResponse; + +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Optional; + +import static io.mailtrap.http.RequestData.entry; + +public class SuppressionsImpl extends ApiResource implements Suppressions { + + public SuppressionsImpl(MailtrapConfig config) { + super(config); + this.apiHost = Constants.GENERAL_HOST; + } + + @Override + public List search(long accountId, String email) { + var queryParams = RequestData.buildQueryParams(entry("email", Optional.ofNullable(email))); + + return + httpClient.getList( + String.format(apiHost + "/api/accounts/%d/suppressions", accountId), + new RequestData(queryParams), + SuppressionsResponse.class + ); + } + + @Override + public SuppressionsResponse deleteSuppression(long accountId, String suppressionId) { + return + httpClient.delete( + String.format(apiHost + "/api/accounts/%d/suppressions/%s", accountId, URLEncoder.encode(suppressionId, Charset.defaultCharset())), + new RequestData(), + SuppressionsResponse.class + ); + } +} diff --git a/src/main/java/io/mailtrap/client/api/MailtrapEmailSendingApi.java b/src/main/java/io/mailtrap/client/api/MailtrapEmailSendingApi.java index 755aa28..acfb776 100644 --- a/src/main/java/io/mailtrap/client/api/MailtrapEmailSendingApi.java +++ b/src/main/java/io/mailtrap/client/api/MailtrapEmailSendingApi.java @@ -2,6 +2,7 @@ import io.mailtrap.api.sendingdomains.SendingDomains; import io.mailtrap.api.sendingemails.SendingEmails; +import io.mailtrap.api.suppressions.Suppressions; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.experimental.Accessors; @@ -15,4 +16,5 @@ public class MailtrapEmailSendingApi { private final SendingEmails emails; private final SendingDomains domains; + private final Suppressions suppressions; } diff --git a/src/main/java/io/mailtrap/factory/MailtrapClientFactory.java b/src/main/java/io/mailtrap/factory/MailtrapClientFactory.java index 1a7f3c9..a13a082 100644 --- a/src/main/java/io/mailtrap/factory/MailtrapClientFactory.java +++ b/src/main/java/io/mailtrap/factory/MailtrapClientFactory.java @@ -16,6 +16,7 @@ import io.mailtrap.api.projects.ProjectsImpl; import io.mailtrap.api.sendingdomains.SendingDomainsImpl; import io.mailtrap.api.sendingemails.SendingEmailsImpl; +import io.mailtrap.api.suppressions.SuppressionsImpl; import io.mailtrap.api.testingemails.TestingEmailsImpl; import io.mailtrap.client.MailtrapClient; import io.mailtrap.client.api.*; @@ -73,8 +74,9 @@ private static MailtrapGeneralApi createGeneralApi(MailtrapConfig config) { private static MailtrapEmailSendingApi createSendingApi(MailtrapConfig config, CustomValidator customValidator) { final var emails = new SendingEmailsImpl(config, customValidator); final var domains = new SendingDomainsImpl(config); + final var suppressions = new SuppressionsImpl(config); - return new MailtrapEmailSendingApi(emails, domains); + return new MailtrapEmailSendingApi(emails, domains, suppressions); } private static MailtrapEmailTestingApi createTestingApi(MailtrapConfig config, CustomValidator customValidator) { diff --git a/src/main/java/io/mailtrap/model/response/suppressions/SendingStream.java b/src/main/java/io/mailtrap/model/response/suppressions/SendingStream.java new file mode 100644 index 0000000..05cc5b4 --- /dev/null +++ b/src/main/java/io/mailtrap/model/response/suppressions/SendingStream.java @@ -0,0 +1,31 @@ +package io.mailtrap.model.response.suppressions; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public enum SendingStream { + ANY("any"), + TRANSACTIONAL("transactional"), + BULK("bulk"); + + private final String value; + + SendingStream(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @JsonCreator + public static SendingStream fromValue(String value) { + for (SendingStream type : SendingStream.values()) { + if (type.value.equalsIgnoreCase(value)) { + return type; + } + } + throw new IllegalArgumentException("Unknown value: " + value); + } +} diff --git a/src/main/java/io/mailtrap/model/response/suppressions/SuppressionType.java b/src/main/java/io/mailtrap/model/response/suppressions/SuppressionType.java new file mode 100644 index 0000000..5dc5630 --- /dev/null +++ b/src/main/java/io/mailtrap/model/response/suppressions/SuppressionType.java @@ -0,0 +1,32 @@ +package io.mailtrap.model.response.suppressions; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public enum SuppressionType { + HARD_BOUNCE("hard bounce"), + SPAM_COMPLAINT("spam complaint"), + UNSUBSCRIPTION("unsubscription"), + MANUAL_IMPORT("manual import"); + + private final String value; + + SuppressionType(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @JsonCreator + public static SuppressionType fromValue(String value) { + for (SuppressionType type : SuppressionType.values()) { + if (type.value.equalsIgnoreCase(value)) { + return type; + } + } + throw new IllegalArgumentException("Unknown value: " + value); + } +} diff --git a/src/main/java/io/mailtrap/model/response/suppressions/SuppressionsResponse.java b/src/main/java/io/mailtrap/model/response/suppressions/SuppressionsResponse.java new file mode 100644 index 0000000..afdb279 --- /dev/null +++ b/src/main/java/io/mailtrap/model/response/suppressions/SuppressionsResponse.java @@ -0,0 +1,52 @@ +package io.mailtrap.model.response.suppressions; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.time.OffsetDateTime; + +@Data +public class SuppressionsResponse { + + @JsonProperty("id") + private String id; + + @JsonProperty("type") + private SuppressionType type; + + @JsonProperty("created_at") + private OffsetDateTime createdAt; + + @JsonProperty("email") + private String email; + + @JsonProperty("sending_stream") + private SendingStream sendingStream; + + @JsonProperty("domain_name") + private String domainName; + + @JsonProperty("message_bounce_category") + private String messageBounceCategory; + + @JsonProperty("message_category") + private String messageCategory; + + @JsonProperty("message_client_ip") + private String messageClientIp; + + @JsonProperty("message_created_at") + private OffsetDateTime messageCreatedAt; + + @JsonProperty("message_outgoing_ip") + private String messageOutgoingIp; + + @JsonProperty("message_recipient_mx_name") + private String messageRecipientMxName; + + @JsonProperty("message_sender_email") + private String messageSenderEmail; + + @JsonProperty("message_subject") + private String messageSubject; +} diff --git a/src/test/java/io/mailtrap/api/suppressions/SuppressionsImplTest.java b/src/test/java/io/mailtrap/api/suppressions/SuppressionsImplTest.java new file mode 100644 index 0000000..4c0460e --- /dev/null +++ b/src/test/java/io/mailtrap/api/suppressions/SuppressionsImplTest.java @@ -0,0 +1,68 @@ +package io.mailtrap.api.suppressions; + +import io.mailtrap.Constants; +import io.mailtrap.config.MailtrapConfig; +import io.mailtrap.factory.MailtrapClientFactory; +import io.mailtrap.model.response.suppressions.SendingStream; +import io.mailtrap.model.response.suppressions.SuppressionType; +import io.mailtrap.model.response.suppressions.SuppressionsResponse; +import io.mailtrap.testutils.BaseTest; +import io.mailtrap.testutils.DataMock; +import io.mailtrap.testutils.TestHttpClient; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class SuppressionsImplTest extends BaseTest { + + private Suppressions api; + + @BeforeEach + public void init() { + TestHttpClient httpClient = new TestHttpClient(List.of( + DataMock.build( + Constants.GENERAL_HOST + "/api/accounts/" + accountId + "/suppressions", + "GET", null, "api/suppressions/searchSuppressions.json", + Map.of("email", email) + ), + DataMock.build( + Constants.GENERAL_HOST + "/api/accounts/" + accountId + "/suppressions/" + suppressionIdEncoded, + "DELETE", null, "api/suppressions/deleteSuppression.json" + ) + )); + + MailtrapConfig testConfig = new MailtrapConfig.Builder() + .httpClient(httpClient) + .token("dummy_token") + .build(); + + api = MailtrapClientFactory.createMailtrapClient(testConfig).sendingApi().suppressions(); + } + + @Test + void test_search() { + List searchResponse = api.search(accountId, email); + + assertEquals(1, searchResponse.size()); + assertEquals(suppressionId, searchResponse.get(0).getId()); + assertEquals(email, searchResponse.get(0).getEmail()); + assertEquals(SendingStream.BULK, searchResponse.get(0).getSendingStream()); + assertEquals(SuppressionType.SPAM_COMPLAINT, searchResponse.get(0).getType()); + } + + @Test + void test_deleteSuppression() { + SuppressionsResponse deleted = api.deleteSuppression(accountId, suppressionId); + + assertNotNull(deleted); + assertEquals(suppressionId, deleted.getId()); + assertEquals(email, deleted.getEmail()); + assertEquals(SendingStream.BULK, deleted.getSendingStream()); + assertEquals(SuppressionType.SPAM_COMPLAINT, deleted.getType()); + } +} diff --git a/src/test/java/io/mailtrap/testutils/BaseTest.java b/src/test/java/io/mailtrap/testutils/BaseTest.java index 821740f..5870868 100644 --- a/src/test/java/io/mailtrap/testutils/BaseTest.java +++ b/src/test/java/io/mailtrap/testutils/BaseTest.java @@ -18,8 +18,9 @@ public class BaseTest { protected final String contactUUID = "018dd5e3-f6d2-7c00-8f9b-e5c3f2d8a132"; protected final String contactUUIDEncoded = URLEncoder.encode(contactUUID, Charset.defaultCharset()); protected final long importId = 1L; - protected final long fieldId = 1L; protected final long getFieldId = 777L; protected final long updateFieldId = 999L; protected final long deleteFieldId = 1111L; + protected final String suppressionId = "2fe148b8-b019-431f-ab3f-107663fdf868"; + protected final String suppressionIdEncoded = URLEncoder.encode(suppressionId, Charset.defaultCharset()); } diff --git a/src/test/resources/api/suppressions/deleteSuppression.json b/src/test/resources/api/suppressions/deleteSuppression.json new file mode 100644 index 0000000..bcee396 --- /dev/null +++ b/src/test/resources/api/suppressions/deleteSuppression.json @@ -0,0 +1,16 @@ +{ + "id": "2fe148b8-b019-431f-ab3f-107663fdf868", + "type": "spam complaint", + "created_at": "2025-09-03T00:40:44.161Z", + "email": "email@mailtrap.io", + "sending_stream": "bulk", + "domain_name": "sender.com", + "message_bounce_category": null, + "message_category": "Welcome email", + "message_client_ip": "123.111.123.111", + "message_created_at": "2025-09-02T00:40:44.161Z", + "message_outgoing_ip": "1.1.1.1", + "message_recipient_mx_name": "Other Providers", + "message_sender_email": "hello-sender@sender.com", + "message_subject": "Welcome!" +} diff --git a/src/test/resources/api/suppressions/searchSuppressions.json b/src/test/resources/api/suppressions/searchSuppressions.json new file mode 100644 index 0000000..c17977b --- /dev/null +++ b/src/test/resources/api/suppressions/searchSuppressions.json @@ -0,0 +1,18 @@ +[ + { + "id": "2fe148b8-b019-431f-ab3f-107663fdf868", + "type": "spam complaint", + "created_at": "2025-09-03T00:40:44.161Z", + "email": "email@mailtrap.io", + "sending_stream": "bulk", + "domain_name": "sender.com", + "message_bounce_category": null, + "message_category": "Welcome email", + "message_client_ip": "123.111.123.111", + "message_created_at": "2025-09-02T00:40:44.161Z", + "message_outgoing_ip": "1.1.1.1", + "message_recipient_mx_name": "Other Providers", + "message_sender_email": "hello-sender@sender.com", + "message_subject": "Welcome!" + } +]