* https://mailersend.com
**************************************************/
-package com.mailsend.sdk.emailverification;
+package com.mailersend.sdk.emailverification;
import com.google.gson.annotations.SerializedName;
diff --git a/src/main/java/com/mailersend/sdk/inboundroutes/InboundFilter.java b/src/main/java/com/mailersend/sdk/inboundroutes/InboundFilter.java
new file mode 100644
index 0000000..1b4fae0
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/inboundroutes/InboundFilter.java
@@ -0,0 +1,60 @@
+package com.mailersend.sdk.inboundroutes;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * InboundFilter class.
+ *
+ * Represents a single filter entry within a {@link MatchFilter} or {@link CatchFilter}.
+ * Valid comparer values are: {@code equal}, {@code not-equal}, {@code contains},
+ * {@code not-contains}, {@code starts-with}, {@code ends-with}, {@code not-starts-with},
+ * {@code not-ends-with}.
+ *
+ * @author mailersend
+ * @version $Id: $Id
+ */
+public class InboundFilter {
+
+ @SerializedName("comparer")
+ public String comparer;
+
+ @SerializedName("value")
+ public String value;
+
+ /**
+ * Optional. Required when the parent filter type is {@code match_header}.
+ */
+ @SerializedName("key")
+ public String key;
+
+ /**
+ * Constructor for InboundFilter.
+ */
+ public InboundFilter() {
+ // intentionally left blank
+ }
+
+ /**
+ * Constructor for InboundFilter.
+ *
+ * @param comparer a {@link java.lang.String} object.
+ * @param value a {@link java.lang.String} object.
+ */
+ public InboundFilter(String comparer, String value) {
+ this.comparer = comparer;
+ this.value = value;
+ }
+
+ /**
+ * Constructor for InboundFilter.
+ *
+ * @param comparer a {@link java.lang.String} object.
+ * @param value a {@link java.lang.String} object.
+ * @param key a {@link java.lang.String} object.
+ */
+ public InboundFilter(String comparer, String value, String key) {
+ this.comparer = comparer;
+ this.value = value;
+ this.key = key;
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/inboundroutes/InboundRouteBuilder.java b/src/main/java/com/mailersend/sdk/inboundroutes/InboundRouteBuilder.java
index 849946d..ea8ce01 100644
--- a/src/main/java/com/mailersend/sdk/inboundroutes/InboundRouteBuilder.java
+++ b/src/main/java/com/mailersend/sdk/inboundroutes/InboundRouteBuilder.java
@@ -1,5 +1,7 @@
package com.mailersend.sdk.inboundroutes;
+import java.util.Arrays;
+
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mailersend.sdk.MailerSend;
@@ -109,6 +111,31 @@ public InboundRouteBuilder inboundPriority(int priority) {
return this;
}
+ /**
+ * catchFilter.
+ *
+ * @param filter a {@link com.mailersend.sdk.inboundroutes.CatchFilter} object.
+ * @return a {@link com.mailersend.sdk.inboundroutes.InboundRouteBuilder} object.
+ */
+ public InboundRouteBuilder catchFilter(CatchFilter filter) {
+ builderBody.catchFilter = filter;
+ return this;
+ }
+
+ /**
+ * catchType.
+ *
+ * Sets the catch type. Must be one of: {@code all}, {@code one}.
+ * Required when the catch filter type is {@code catch_recipient}.
+ *
+ * @param catchType a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.inboundroutes.InboundRouteBuilder} object.
+ */
+ public InboundRouteBuilder catchType(String catchType) {
+ builderBody.catchType = catchType;
+ return this;
+ }
+
/**
* matchFilter.
*
@@ -121,15 +148,34 @@ public InboundRouteBuilder matchFilter(String type) {
builderBody.matchFilter = filter;
return this;
}
-
+
/**
- * catchFilter.
+ * matchFilter.
*
- * @param filter a {@link com.mailersend.sdk.inboundroutes.CatchFilter} object.
+ * Sets the match filter with a type and an array of sub-filters. The {@code filters}
+ * array is required when type is not {@code match_all}.
+ *
+ * @param type a {@link java.lang.String} object.
+ * @param filters an array of {@link com.mailersend.sdk.inboundroutes.InboundFilter} objects.
* @return a {@link com.mailersend.sdk.inboundroutes.InboundRouteBuilder} object.
*/
- public InboundRouteBuilder catchFilter(CatchFilter filter) {
- builderBody.catchFilter = filter;
+ public InboundRouteBuilder matchFilter(String type, InboundFilter[] filters) {
+ builderBody.matchFilter = new MatchFilter(type, filters);
+ return this;
+ }
+
+ /**
+ * matchType.
+ *
+ * Sets the match type. Must be one of: {@code all}, {@code one}.
+ * Required when the match filter type is {@code match_sender}, {@code match_domain},
+ * or {@code match_header}.
+ *
+ * @param matchType a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.inboundroutes.InboundRouteBuilder} object.
+ */
+ public InboundRouteBuilder matchType(String matchType) {
+ builderBody.matchType = matchType;
return this;
}
@@ -145,6 +191,70 @@ public InboundRouteBuilder forwards(Forward[] forwards) {
}
+ private static final String[] VALID_CATCH_FILTER_TYPES = {"catch_all", "catch_recipient"};
+ private static final String[] VALID_CATCH_TYPES = {"all", "one"};
+ private static final String[] VALID_COMPARERS = {
+ "equal", "not-equal", "contains", "not-contains",
+ "starts-with", "ends-with", "not-starts-with", "not-ends-with"
+ };
+ private static final String MATCH_HEADER_TYPE = "match_header";
+
+ /**
+ * Validates the builder body before sending a request.
+ *
+ * @throws MailerSendException if any required field is missing or any value is invalid.
+ */
+ private void validate() throws MailerSendException {
+
+ if (builderBody.domainEnabled && (builderBody.inboundDomain == null || builderBody.inboundDomain.isBlank())) {
+ throw new MailerSendException("inbound_domain is required when domain_enabled is true");
+ }
+
+ if (builderBody.inboundPriority < 0 || builderBody.inboundPriority > 100) {
+ throw new MailerSendException("inbound_priority must be between 0 and 100");
+ }
+
+ if (builderBody.catchFilter != null) {
+ CatchFilter cf = builderBody.catchFilter;
+
+ if (cf.type == null || !Arrays.asList(VALID_CATCH_FILTER_TYPES).contains(cf.type)) {
+ throw new MailerSendException("catch_filter.type must be one of: catch_all, catch_recipient");
+ }
+
+ if (cf.filters != null && cf.filters.length > 5) {
+ throw new MailerSendException("catch_filter.filters must not exceed 5 items");
+ }
+
+ if (cf.filters != null) {
+ for (Filter filter : cf.filters) {
+ if (filter.comparer != null && !Arrays.asList(VALID_COMPARERS).contains(filter.comparer)) {
+ throw new MailerSendException("catch_filter.filters.comparer must be one of: equal, not-equal, contains, not-contains, starts-with, ends-with, not-starts-with, not-ends-with");
+ }
+ }
+ }
+ }
+
+ if (builderBody.catchType != null && !Arrays.asList(VALID_CATCH_TYPES).contains(builderBody.catchType)) {
+ throw new MailerSendException("catch_type must be one of: all, one");
+ }
+
+ if (builderBody.matchFilter != null) {
+ MatchFilter mf = builderBody.matchFilter;
+
+ if (mf.filters != null) {
+ for (InboundFilter filter : mf.filters) {
+ if (MATCH_HEADER_TYPE.equals(mf.type) && (filter.key == null || filter.key.isBlank())) {
+ throw new MailerSendException("match_filter.filters.key is required when match_filter.type is match_header");
+ }
+
+ if (filter.comparer != null && !Arrays.asList(VALID_COMPARERS).contains(filter.comparer)) {
+ throw new MailerSendException("match_filter.filters.comparer must be one of: equal, not-equal, contains, not-contains, starts-with, ends-with, not-starts-with, not-ends-with");
+ }
+ }
+ }
+ }
+ }
+
/**
* addRoute.
*
@@ -152,7 +262,9 @@ public InboundRouteBuilder forwards(Forward[] forwards) {
* @throws com.mailersend.sdk.exceptions.MailerSendException if any.
*/
public InboundRoute addRoute() throws MailerSendException {
-
+
+ validate();
+
String endpoint = "/inbound";
MailerSendApi api = new MailerSendApi();
@@ -180,6 +292,9 @@ public InboundRoute addRoute() throws MailerSendException {
* @throws com.mailersend.sdk.exceptions.MailerSendException if any.
*/
public InboundRoute updateRoute(String inboundRouteId) throws MailerSendException {
+
+ validate();
+
String endpoint = "/inbound/" + inboundRouteId;
MailerSendApi api = new MailerSendApi();
diff --git a/src/main/java/com/mailersend/sdk/inboundroutes/InboundRouteBuilderBody.java b/src/main/java/com/mailersend/sdk/inboundroutes/InboundRouteBuilderBody.java
index 4d6c738..82df048 100644
--- a/src/main/java/com/mailersend/sdk/inboundroutes/InboundRouteBuilderBody.java
+++ b/src/main/java/com/mailersend/sdk/inboundroutes/InboundRouteBuilderBody.java
@@ -31,15 +31,30 @@ public class InboundRouteBuilderBody {
@SerializedName("inbound_priority")
public int inboundPriority;
- @SerializedName("match_filter")
- public MatchFilter matchFilter;
-
@SerializedName("catch_filter")
public CatchFilter catchFilter;
-
+
+ /**
+ * Optional. Must be one of: {@code all}, {@code one}.
+ * Required when {@code catch_filter.type} is {@code catch_recipient}.
+ */
+ @SerializedName("catch_type")
+ public String catchType;
+
+ @SerializedName("match_filter")
+ public MatchFilter matchFilter;
+
+ /**
+ * Optional. Must be one of: {@code all}, {@code one}.
+ * Required when {@code match_filter.type} is {@code match_sender}, {@code match_domain},
+ * or {@code match_header}.
+ */
+ @SerializedName("match_type")
+ public String matchType;
+
@SerializedName("forwards")
public Forward[] forwards;
-
+
/**
* reset.
*/
@@ -51,8 +66,10 @@ public void reset() {
inboundAddress = null;
inboundSubdomain = null;
inboundPriority = 0;
- matchFilter = null;
catchFilter = null;
+ catchType = null;
+ matchFilter = null;
+ matchType = null;
forwards = null;
}
}
diff --git a/src/main/java/com/mailersend/sdk/inboundroutes/MatchFilter.java b/src/main/java/com/mailersend/sdk/inboundroutes/MatchFilter.java
index cf20deb..ab786c4 100644
--- a/src/main/java/com/mailersend/sdk/inboundroutes/MatchFilter.java
+++ b/src/main/java/com/mailersend/sdk/inboundroutes/MatchFilter.java
@@ -5,6 +5,10 @@
/**
* MatchFilter class.
*
+ * Valid type values: {@code match_all}, {@code match_sender}, {@code match_domain},
+ * {@code match_header}. The {@code filters} array is required when type is not
+ * {@code match_all}.
+ *
* @author mailersend
* @version $Id: $Id
*/
@@ -12,4 +16,25 @@ public class MatchFilter {
@SerializedName("type")
public String type;
+
+ @SerializedName("filters")
+ public InboundFilter[] filters;
+
+ /**
+ * Constructor for MatchFilter.
+ */
+ public MatchFilter() {
+ // intentionally left blank
+ }
+
+ /**
+ * Constructor for MatchFilter.
+ *
+ * @param type a {@link java.lang.String} object.
+ * @param filters an array of {@link com.mailersend.sdk.inboundroutes.InboundFilter} objects.
+ */
+ public MatchFilter(String type, InboundFilter[] filters) {
+ this.type = type;
+ this.filters = filters;
+ }
}
diff --git a/src/main/java/com/mailersend/sdk/recipients/Recipient.java b/src/main/java/com/mailersend/sdk/recipients/Recipient.java
index 2a45b1b..3f036d9 100644
--- a/src/main/java/com/mailersend/sdk/recipients/Recipient.java
+++ b/src/main/java/com/mailersend/sdk/recipients/Recipient.java
@@ -14,6 +14,7 @@
import com.google.gson.annotations.SerializedName;
import com.mailersend.sdk.domains.Domain;
+import com.mailersend.sdk.util.ApiEmail;
/**
* Recipient class.
@@ -39,9 +40,12 @@ public class Recipient {
@SerializedName("deleted_at")
private String deletedAtString;
+ @SerializedName("emails")
+ public ApiEmail[] emails;
+
@SerializedName("domain")
public Domain domain;
-
+
public Date createdAt;
public Date updatedAt;
@@ -73,13 +77,24 @@ protected void parseDates() {
}
if (deletedAtString != null && !deletedAtString.isBlank()) {
-
+
ta = DateTimeFormatter.ISO_INSTANT.parse(deletedAtString);
instant = Instant.from(ta);
deletedAt = Date.from(instant);
}
-
- domain.postDeserialize();
+
+ if (domain != null) {
+
+ domain.postDeserialize();
+ }
+
+ if (emails != null) {
+
+ for (ApiEmail email : emails) {
+
+ email.parseDates();
+ }
+ }
}
}
diff --git a/src/main/java/com/mailersend/sdk/recipients/Recipients.java b/src/main/java/com/mailersend/sdk/recipients/Recipients.java
index 5c63c50..ce870f9 100644
--- a/src/main/java/com/mailersend/sdk/recipients/Recipients.java
+++ b/src/main/java/com/mailersend/sdk/recipients/Recipients.java
@@ -12,7 +12,6 @@
import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.MailerSendApi;
import com.mailersend.sdk.MailerSendResponse;
-import com.mailersend.sdk.domains.DomainsList;
import com.mailersend.sdk.exceptions.MailerSendException;
import com.mailersend.sdk.util.ApiRecipientsList;
@@ -76,11 +75,17 @@ public Recipients page(int page) {
*
* @param limit a int.
* @return a {@link com.mailersend.sdk.recipients.Recipients} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException if limit is not between 10 and 100.
*/
- public Recipients limit(int limit) {
-
+ public Recipients limit(int limit) throws MailerSendException {
+
+ if (limit < 10 || limit > 100) {
+
+ throw new MailerSendException("Limit must be between 10 and 100");
+ }
+
limitFilter = limit;
-
+
return this;
}
diff --git a/src/main/java/com/mailersend/sdk/recipients/SuppressionItem.java b/src/main/java/com/mailersend/sdk/recipients/SuppressionItem.java
index 673ddfd..34a27e5 100644
--- a/src/main/java/com/mailersend/sdk/recipients/SuppressionItem.java
+++ b/src/main/java/com/mailersend/sdk/recipients/SuppressionItem.java
@@ -22,7 +22,13 @@ public class SuppressionItem {
@SerializedName("reason")
public String reason;
-
+
+ @SerializedName("readable_reason")
+ public String readableReason;
+
+ @SerializedName("created_at")
+ public String createdAt;
+
@SerializedName("recipient")
public Recipient recipient;
}
diff --git a/src/main/java/com/mailersend/sdk/recipients/Suppressions.java b/src/main/java/com/mailersend/sdk/recipients/Suppressions.java
index df4aeb2..66cf790 100644
--- a/src/main/java/com/mailersend/sdk/recipients/Suppressions.java
+++ b/src/main/java/com/mailersend/sdk/recipients/Suppressions.java
@@ -28,7 +28,7 @@ public class Suppressions {
private MailerSend apiObjectReference;
private int pageFilter = 1;
- private int limitFilter = 25;
+ private int limitFilter = 10;
private String domainIdFilter = null;
private SuppressionAddBuilder addBuilder;
@@ -261,7 +261,7 @@ public MailerSendResponse deleteSpamComplaintsAllItems() throws MailerSendExcept
*/
public MailerSendResponse deleteUnsubscribesItems(String[] ids) throws MailerSendException {
- return this.deleteSuppressionListItems("/suppressions/unsubscribres", ids);
+ return this.deleteSuppressionListItems("/suppressions/unsubscribes", ids);
}
@@ -272,11 +272,50 @@ public MailerSendResponse deleteUnsubscribesItems(String[] ids) throws MailerSen
* @return a {@link com.mailersend.sdk.MailerSendResponse} object.
*/
public MailerSendResponse deleteUnsubscribesAllItems() throws MailerSendException {
-
+
return this.deleteSuppressionListAllItems("/suppressions/unsubscribes");
}
-
-
+
+
+ /**
+ * Gets the recipients on the on-hold list
+ *
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.recipients.SuppressionList} object.
+ */
+ public SuppressionList getOnHoldList() throws MailerSendException {
+
+ String endpoint = "/suppressions/on-hold-list".concat(prepareParamsUrl());
+
+ return this.getSuppressionList(endpoint);
+ }
+
+
+ /**
+ * Deletes the items with the given id from the on-hold suppression list
+ *
+ * @param ids an array of {@link java.lang.String} objects.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.MailerSendResponse} object.
+ */
+ public MailerSendResponse deleteOnHoldListItems(String[] ids) throws MailerSendException {
+
+ return this.deleteSuppressionListItems("/suppressions/on-hold-list", ids);
+ }
+
+
+ /**
+ * Deletes all items from the on-hold suppression list
+ *
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.MailerSendResponse} object.
+ */
+ public MailerSendResponse deleteOnHoldListAllItems() throws MailerSendException {
+
+ return this.deleteSuppressionListAllItems("/suppressions/on-hold-list");
+ }
+
+
/**
* Deletes the items with the given id from the suppression list with the given endpoint
* @param ids
diff --git a/src/main/java/com/mailersend/sdk/scheduledmessages/ScheduledMessage.java b/src/main/java/com/mailersend/sdk/scheduledmessages/ScheduledMessage.java
index 8dd478f..90655b3 100644
--- a/src/main/java/com/mailersend/sdk/scheduledmessages/ScheduledMessage.java
+++ b/src/main/java/com/mailersend/sdk/scheduledmessages/ScheduledMessage.java
@@ -15,6 +15,9 @@
*/
public class ScheduledMessage {
+ @SerializedName("id")
+ public String id;
+
@SerializedName("message_id")
public String messageId;
diff --git a/src/main/java/com/mailersend/sdk/scheduledmessages/ScheduledMessages.java b/src/main/java/com/mailersend/sdk/scheduledmessages/ScheduledMessages.java
index f91bd74..915fd40 100644
--- a/src/main/java/com/mailersend/sdk/scheduledmessages/ScheduledMessages.java
+++ b/src/main/java/com/mailersend/sdk/scheduledmessages/ScheduledMessages.java
@@ -16,8 +16,17 @@
*/
public class ScheduledMessages {
+ /** Status constant for messages that are scheduled for future delivery. */
+ public static final String STATUS_SCHEDULED = "scheduled";
+
+ /** Status constant for messages that have been successfully sent. */
+ public static final String STATUS_SENT = "sent";
+
+ /** Status constant for messages that encountered an error during delivery. */
+ public static final String STATUS_ERROR = "error";
+
private MailerSend apiObjectReference;
-
+
private int pageFilter = 1;
private int limitFilter = 25;
private String domainIdFilter;
diff --git a/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentities.java b/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentities.java
new file mode 100644
index 0000000..ddd78de
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentities.java
@@ -0,0 +1,314 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.senderidentities;
+
+import java.util.ArrayList;
+import java.util.stream.IntStream;
+
+import com.mailersend.sdk.MailerSend;
+import com.mailersend.sdk.MailerSendApi;
+import com.mailersend.sdk.MailerSendResponse;
+import com.mailersend.sdk.exceptions.MailerSendException;
+
+/**
+ * Provides access to the Sender Identities API endpoints.
+ *
+ * Do not initialize directly — access via {@code MailerSend.senderIdentities()}.
+ *
+ * @author mailersend
+ */
+public class SenderIdentities {
+
+ private MailerSend apiObjectReference;
+
+ private SenderIdentityBuilder identityBuilder;
+
+ private int pageFilter = 1;
+ private int limitFilter = 25;
+ private String domainIdFilter = null;
+ private String queryFilter = null;
+ private String orderByFilter = null;
+ private String orderFilter = null;
+
+
+ /**
+ * Do not initialize directly. This should only be accessed from MailerSend.senderIdentities().
+ *
+ * @param ref a {@link com.mailersend.sdk.MailerSend} object.
+ */
+ public SenderIdentities(MailerSend ref) {
+
+ apiObjectReference = ref;
+ identityBuilder = new SenderIdentityBuilder(ref);
+ }
+
+
+ /**
+ * Returns the builder used to create or update sender identities.
+ *
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentityBuilder} object.
+ */
+ public SenderIdentityBuilder builder() {
+
+ return identityBuilder;
+ }
+
+
+ /**
+ * Set the page for list requests.
+ *
+ * @param page a int.
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentities} object.
+ */
+ public SenderIdentities page(int page) {
+
+ pageFilter = page;
+
+ return this;
+ }
+
+
+ /**
+ * Set the results limit for list requests (10–100).
+ *
+ * @param limit a int.
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentities} object.
+ */
+ public SenderIdentities limit(int limit) {
+
+ limitFilter = limit;
+
+ return this;
+ }
+
+
+ /**
+ * Filter identities by domain ID.
+ *
+ * @param domainId a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentities} object.
+ */
+ public SenderIdentities domainId(String domainId) {
+
+ domainIdFilter = domainId;
+
+ return this;
+ }
+
+
+ /**
+ * Filter identities by email address (partial match).
+ *
+ * @param query a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentities} object.
+ */
+ public SenderIdentities query(String query) {
+
+ queryFilter = query;
+
+ return this;
+ }
+
+
+ /**
+ * Set the field to order list results by.
+ * Valid values: {@code email}, {@code created_at}, {@code verified_at}.
+ *
+ * @param orderBy a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentities} object.
+ */
+ public SenderIdentities orderBy(String orderBy) {
+
+ orderByFilter = orderBy;
+
+ return this;
+ }
+
+
+ /**
+ * Set the sort direction for list results.
+ * Valid values: {@code asc}, {@code desc}.
+ *
+ * @param order a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentities} object.
+ */
+ public SenderIdentities order(String order) {
+
+ orderFilter = order;
+
+ return this;
+ }
+
+
+ /**
+ * Retrieves a paginated list of sender identities.
+ *
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentitiesList} object.
+ */
+ public SenderIdentitiesList getIdentities() throws MailerSendException {
+
+ String endpoint = "/identities".concat(prepareParamsUrl());
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ SenderIdentitiesList response = api.getRequest(endpoint, SenderIdentitiesList.class);
+
+ if (response.identities != null) {
+ for (SenderIdentity identity : response.identities) {
+ identity.postDeserialize();
+ }
+ }
+
+ return response;
+ }
+
+
+ /**
+ * Retrieves a single sender identity by its ID.
+ *
+ * @param identityId a {@link java.lang.String} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentity} object.
+ */
+ public SenderIdentity getIdentity(String identityId) throws MailerSendException {
+
+ String endpoint = "/identities/".concat(identityId);
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ SingleSenderIdentityResponse response = api.getRequest(endpoint, SingleSenderIdentityResponse.class);
+
+ response.identity.postDeserialize();
+
+ return response.identity;
+ }
+
+
+ /**
+ * Retrieves a single sender identity by its email address.
+ *
+ * @param email a {@link java.lang.String} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentity} object.
+ */
+ public SenderIdentity getIdentityByEmail(String email) throws MailerSendException {
+
+ String endpoint = "/identities/email/".concat(email);
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ SingleSenderIdentityResponse response = api.getRequest(endpoint, SingleSenderIdentityResponse.class);
+
+ response.identity.postDeserialize();
+
+ return response.identity;
+ }
+
+
+ /**
+ * Deletes the sender identity with the given ID.
+ *
+ * @param identityId a {@link java.lang.String} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return {@code true} if the deletion was accepted (HTTP 200, 202, or 204).
+ */
+ public boolean deleteIdentity(String identityId) throws MailerSendException {
+
+ String endpoint = "/identities/".concat(identityId);
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ MailerSendResponse response = api.deleteRequest(endpoint, MailerSendResponse.class);
+
+ return IntStream.of(new int[]{200, 202, 204}).anyMatch(x -> x == response.responseStatusCode);
+ }
+
+
+ /**
+ * Deletes the sender identity with the given email address.
+ *
+ * @param email a {@link java.lang.String} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return {@code true} if the deletion was accepted (HTTP 200, 202, or 204).
+ */
+ public boolean deleteIdentityByEmail(String email) throws MailerSendException {
+
+ String endpoint = "/identities/email/".concat(email);
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ MailerSendResponse response = api.deleteRequest(endpoint, MailerSendResponse.class);
+
+ return IntStream.of(new int[]{200, 202, 204}).anyMatch(x -> x == response.responseStatusCode);
+ }
+
+
+ /**
+ * Resends the confirmation email for the sender identity with the given ID.
+ *
+ * @param identityId a {@link java.lang.String} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentity} object.
+ */
+ public SenderIdentity resendConfirmation(String identityId) throws MailerSendException {
+
+ String endpoint = "/identities/".concat(identityId).concat("/resend");
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ SingleSenderIdentityResponse response = api.postRequest(endpoint, "", SingleSenderIdentityResponse.class);
+
+ response.identity.postDeserialize();
+
+ return response.identity;
+ }
+
+
+ /**
+ * Builds the query-string portion of the list endpoint URL.
+ */
+ private String prepareParamsUrl() {
+
+ ArrayList params = new ArrayList();
+
+ params.add("page=".concat(String.valueOf(pageFilter)));
+ params.add("limit=".concat(String.valueOf(limitFilter)));
+
+ if (domainIdFilter != null && !domainIdFilter.isBlank()) {
+ params.add("domain_id=".concat(domainIdFilter));
+ }
+
+ if (queryFilter != null && !queryFilter.isBlank()) {
+ params.add("query=".concat(queryFilter));
+ }
+
+ if (orderByFilter != null && !orderByFilter.isBlank()) {
+ params.add("order_by=".concat(orderByFilter));
+ }
+
+ if (orderFilter != null && !orderFilter.isBlank()) {
+ params.add("order=".concat(orderFilter));
+ }
+
+ String requestParams = "";
+ for (int i = 0; i < params.size(); i++) {
+
+ String attrSep = i == 0 ? "?" : "&";
+ requestParams = requestParams.concat(attrSep).concat(params.get(i));
+ }
+
+ return requestParams;
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentitiesList.java b/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentitiesList.java
new file mode 100644
index 0000000..3f41f8b
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentitiesList.java
@@ -0,0 +1,22 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.senderidentities;
+
+import com.google.gson.annotations.SerializedName;
+import com.mailersend.sdk.util.PaginatedResponse;
+
+/**
+ * Represents a paginated list of sender identities.
+ *
+ * @author mailersend
+ */
+public class SenderIdentitiesList extends PaginatedResponse {
+
+ @SerializedName("data")
+ public SenderIdentity[] identities;
+}
diff --git a/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentity.java b/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentity.java
new file mode 100644
index 0000000..10b01e6
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentity.java
@@ -0,0 +1,61 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.senderidentities;
+
+import com.google.gson.annotations.SerializedName;
+import com.mailersend.sdk.MailerSendResponse;
+
+/**
+ * Represents a sender identity returned from the MailerSend API.
+ *
+ * @author mailersend
+ */
+public class SenderIdentity extends MailerSendResponse {
+
+ @SerializedName("id")
+ public String id;
+
+ @SerializedName("email")
+ public String email;
+
+ @SerializedName("name")
+ public String name;
+
+ @SerializedName("reply_to_email")
+ public String replyToEmail;
+
+ @SerializedName("reply_to_name")
+ public String replyToName;
+
+ @SerializedName("is_verified")
+ public boolean isVerified;
+
+ @SerializedName("resends")
+ public int resends;
+
+ @SerializedName("add_note")
+ public boolean addNote;
+
+ @SerializedName("personal_note")
+ public String personalNote;
+
+ @SerializedName("domain")
+ public SenderIdentityDomain domain;
+
+
+ /**
+ * Is called to perform any actions after deserialization of the response.
+ * Do not call directly.
+ */
+ public void postDeserialize() {
+
+ if (domain != null) {
+ domain.postDeserialize();
+ }
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentityBody.java b/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentityBody.java
new file mode 100644
index 0000000..1701187
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentityBody.java
@@ -0,0 +1,53 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.senderidentities;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Request body used by SenderIdentityBuilder for create/update calls.
+ * Do not use directly.
+ */
+class SenderIdentityBody {
+
+ @SerializedName("domain_id")
+ public String domainId = null;
+
+ @SerializedName("email")
+ public String email = null;
+
+ @SerializedName("name")
+ public String name = null;
+
+ @SerializedName("reply_to_email")
+ public String replyToEmail = null;
+
+ @SerializedName("reply_to_name")
+ public String replyToName = null;
+
+ @SerializedName("add_note")
+ public Boolean addNote = null;
+
+ @SerializedName("personal_note")
+ public String personalNote = null;
+
+
+ /**
+ * Resets all fields so the builder can be reused.
+ */
+ public void reset() {
+
+ domainId = null;
+ email = null;
+ name = null;
+ replyToEmail = null;
+ replyToName = null;
+ addNote = null;
+ personalNote = null;
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentityBuilder.java b/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentityBuilder.java
new file mode 100644
index 0000000..9abf71f
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentityBuilder.java
@@ -0,0 +1,248 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.senderidentities;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.mailersend.sdk.MailerSend;
+import com.mailersend.sdk.MailerSendApi;
+import com.mailersend.sdk.exceptions.MailerSendException;
+import com.mailersend.sdk.util.JsonSerializationDeserializationStrategy;
+
+/**
+ * Builder for creating and updating sender identities.
+ *
+ * @author mailersend
+ */
+public class SenderIdentityBuilder {
+
+ private MailerSend apiObjectReference;
+
+ private SenderIdentityBody builderBody;
+
+
+ /**
+ * No instantiation from outside the SDK.
+ *
+ * @param apiObjectRef a {@link com.mailersend.sdk.MailerSend} object.
+ */
+ protected SenderIdentityBuilder(MailerSend apiObjectRef) {
+
+ apiObjectReference = apiObjectRef;
+ builderBody = new SenderIdentityBody();
+ }
+
+
+ /**
+ * Set the domain ID for the identity (required for create).
+ *
+ * @param domainId a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentityBuilder} object.
+ */
+ public SenderIdentityBuilder domainId(String domainId) {
+
+ builderBody.domainId = domainId;
+
+ return this;
+ }
+
+
+ /**
+ * Set the email address for the identity (required for create).
+ *
+ * @param email a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentityBuilder} object.
+ */
+ public SenderIdentityBuilder email(String email) {
+
+ builderBody.email = email;
+
+ return this;
+ }
+
+
+ /**
+ * Set the display name for the identity.
+ *
+ * @param name a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentityBuilder} object.
+ */
+ public SenderIdentityBuilder name(String name) {
+
+ builderBody.name = name;
+
+ return this;
+ }
+
+
+ /**
+ * Set the reply-to email address.
+ *
+ * @param replyToEmail a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentityBuilder} object.
+ */
+ public SenderIdentityBuilder replyToEmail(String replyToEmail) {
+
+ builderBody.replyToEmail = replyToEmail;
+
+ return this;
+ }
+
+
+ /**
+ * Set the reply-to display name.
+ *
+ * @param replyToName a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentityBuilder} object.
+ */
+ public SenderIdentityBuilder replyToName(String replyToName) {
+
+ builderBody.replyToName = replyToName;
+
+ return this;
+ }
+
+
+ /**
+ * Set whether to add a personal note to the confirmation email.
+ *
+ * @param addNote a boolean.
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentityBuilder} object.
+ */
+ public SenderIdentityBuilder addNote(boolean addNote) {
+
+ builderBody.addNote = addNote;
+
+ return this;
+ }
+
+
+ /**
+ * Set the personal note text included in the confirmation email.
+ *
+ * @param personalNote a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentityBuilder} object.
+ */
+ public SenderIdentityBuilder personalNote(String personalNote) {
+
+ builderBody.personalNote = personalNote;
+
+ return this;
+ }
+
+
+ /**
+ * Creates a new sender identity.
+ *
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentity} object.
+ */
+ public SenderIdentity createIdentity() throws MailerSendException {
+
+ if (builderBody.domainId == null || builderBody.domainId.isBlank()) {
+
+ throw new MailerSendException("Domain ID cannot be empty");
+ }
+
+ if (builderBody.email == null || builderBody.email.isBlank()) {
+
+ throw new MailerSendException("Email cannot be empty");
+ }
+
+ String endpoint = "/identities";
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ Gson gson = new GsonBuilder()
+ .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false))
+ .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true))
+ .create();
+
+ String json = gson.toJson(builderBody);
+
+ builderBody.reset();
+
+ SingleSenderIdentityResponse response = api.postRequest(endpoint, json, SingleSenderIdentityResponse.class);
+
+ response.identity.postDeserialize();
+
+ return response.identity;
+ }
+
+
+ /**
+ * Updates the sender identity with the given ID.
+ *
+ * @param identityId a {@link java.lang.String} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentity} object.
+ */
+ public SenderIdentity updateIdentity(String identityId) throws MailerSendException {
+
+ if (identityId == null || identityId.isBlank()) {
+
+ throw new MailerSendException("Identity ID cannot be empty");
+ }
+
+ String endpoint = "/identities/".concat(identityId);
+
+ return performUpdate(endpoint);
+ }
+
+
+ /**
+ * Updates the sender identity with the given email address.
+ *
+ * @param email a {@link java.lang.String} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.senderidentities.SenderIdentity} object.
+ */
+ public SenderIdentity updateIdentityByEmail(String email) throws MailerSendException {
+
+ if (email == null || email.isBlank()) {
+
+ throw new MailerSendException("Email cannot be empty");
+ }
+
+ String endpoint = "/identities/email/".concat(email);
+
+ return performUpdate(endpoint);
+ }
+
+
+ /**
+ * Shared PUT logic for update methods.
+ * Only name, reply_to_email, and reply_to_name are sent to the API on update.
+ */
+ private SenderIdentity performUpdate(String endpoint) throws MailerSendException {
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ SenderIdentityUpdateBody updateBody = new SenderIdentityUpdateBody();
+ updateBody.name = builderBody.name;
+ updateBody.replyToEmail = builderBody.replyToEmail;
+ updateBody.replyToName = builderBody.replyToName;
+
+ Gson gson = new GsonBuilder()
+ .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false))
+ .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true))
+ .create();
+
+ String json = gson.toJson(updateBody);
+
+ builderBody.reset();
+
+ SingleSenderIdentityResponse response = api.putRequest(endpoint, json, SingleSenderIdentityResponse.class);
+
+ response.identity.postDeserialize();
+
+ return response.identity;
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentityDomain.java b/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentityDomain.java
new file mode 100644
index 0000000..05fe731
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentityDomain.java
@@ -0,0 +1,67 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.senderidentities;
+
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.util.Date;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Represents the domain object embedded in a sender identity response.
+ */
+public class SenderIdentityDomain {
+
+ @SerializedName("id")
+ public String id;
+
+ @SerializedName("name")
+ public String name;
+
+ @SerializedName("created_at")
+ private String createdAtStr;
+
+ @SerializedName("updated_at")
+ private String updatedAtStr;
+
+ public Date createdAt;
+
+ public Date updatedAt;
+
+
+ /**
+ * Called after deserialization to parse date strings into Date objects.
+ */
+ public void postDeserialize() {
+
+ parseDates();
+ }
+
+
+ private void parseDates() {
+
+ TemporalAccessor ta;
+ Instant instant;
+
+ if (createdAtStr != null && !createdAtStr.isBlank()) {
+
+ ta = DateTimeFormatter.ISO_INSTANT.parse(createdAtStr);
+ instant = Instant.from(ta);
+ createdAt = Date.from(instant);
+ }
+
+ if (updatedAtStr != null && !updatedAtStr.isBlank()) {
+
+ ta = DateTimeFormatter.ISO_INSTANT.parse(updatedAtStr);
+ instant = Instant.from(ta);
+ updatedAt = Date.from(instant);
+ }
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentityUpdateBody.java b/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentityUpdateBody.java
new file mode 100644
index 0000000..3fb6000
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/senderidentities/SenderIdentityUpdateBody.java
@@ -0,0 +1,27 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.senderidentities;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Request body for PUT (update) sender identity calls.
+ * Only the fields accepted by the API on update are included:
+ * {@code name}, {@code reply_to_email}, and {@code reply_to_name}.
+ */
+class SenderIdentityUpdateBody {
+
+ @SerializedName("name")
+ public String name = null;
+
+ @SerializedName("reply_to_email")
+ public String replyToEmail = null;
+
+ @SerializedName("reply_to_name")
+ public String replyToName = null;
+}
diff --git a/src/main/java/com/mailersend/sdk/senderidentities/SingleSenderIdentityResponse.java b/src/main/java/com/mailersend/sdk/senderidentities/SingleSenderIdentityResponse.java
new file mode 100644
index 0000000..70e4846
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/senderidentities/SingleSenderIdentityResponse.java
@@ -0,0 +1,21 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.senderidentities;
+
+import com.google.gson.annotations.SerializedName;
+import com.mailersend.sdk.MailerSendResponse;
+
+/**
+ * Wraps a single sender identity API response.
+ * Do not use directly.
+ */
+public class SingleSenderIdentityResponse extends MailerSendResponse {
+
+ @SerializedName("data")
+ public SenderIdentity identity;
+}
diff --git a/src/main/java/com/mailersend/sdk/sms/activities/SmsActivities.java b/src/main/java/com/mailersend/sdk/sms/activities/SmsActivities.java
index 31a760a..c6408ca 100644
--- a/src/main/java/com/mailersend/sdk/sms/activities/SmsActivities.java
+++ b/src/main/java/com/mailersend/sdk/sms/activities/SmsActivities.java
@@ -153,7 +153,7 @@ public SmsActivityList getActivities() throws MailerSendException {
*/
public SmsMessageActivity getMessageActivity(String messageId) throws MailerSendException {
- String endpoint = "/sms-activity/".concat(messageId);
+ String endpoint = "/sms-messages/".concat(messageId);
MailerSendApi api = new MailerSendApi();
api.setToken(apiObjectReference.getToken());
diff --git a/src/main/java/com/mailersend/sdk/sms/inboundroutes/SmsInboundRoutes.java b/src/main/java/com/mailersend/sdk/sms/inboundroutes/SmsInboundRoutes.java
index 9617177..29b69cc 100644
--- a/src/main/java/com/mailersend/sdk/sms/inboundroutes/SmsInboundRoutes.java
+++ b/src/main/java/com/mailersend/sdk/sms/inboundroutes/SmsInboundRoutes.java
@@ -180,7 +180,7 @@ private String prepareParamsUrl() {
params.add("limit=".concat(String.valueOf(limitFilter)));
if (smsNumberIdFilter != null) {
- params.add("sms_numnber_id=".concat(smsNumberIdFilter));
+ params.add("sms_number_id=".concat(smsNumberIdFilter));
}
if (enabledFilter != null) {
diff --git a/src/main/java/com/mailersend/sdk/smtpusers/SingleSmtpUserResponse.java b/src/main/java/com/mailersend/sdk/smtpusers/SingleSmtpUserResponse.java
new file mode 100644
index 0000000..21c2f5a
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/smtpusers/SingleSmtpUserResponse.java
@@ -0,0 +1,23 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.smtpusers;
+
+import com.google.gson.annotations.SerializedName;
+import com.mailersend.sdk.MailerSendResponse;
+
+/**
+ * SingleSmtpUserResponse class.
+ *
+ * @author mailersend
+ * @version $Id: $Id
+ */
+public class SingleSmtpUserResponse extends MailerSendResponse {
+
+ @SerializedName("data")
+ public SmtpUser smtpUser;
+}
diff --git a/src/main/java/com/mailersend/sdk/smtpusers/SmtpUser.java b/src/main/java/com/mailersend/sdk/smtpusers/SmtpUser.java
new file mode 100644
index 0000000..baf3a38
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/smtpusers/SmtpUser.java
@@ -0,0 +1,47 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.smtpusers;
+
+import com.google.gson.annotations.SerializedName;
+import com.mailersend.sdk.MailerSendResponse;
+
+/**
+ * SmtpUser class.
+ *
+ * @author mailersend
+ * @version $Id: $Id
+ */
+public class SmtpUser extends MailerSendResponse {
+
+ @SerializedName("id")
+ public String id;
+
+ @SerializedName("name")
+ public String name;
+
+ @SerializedName("username")
+ public String username;
+
+ @SerializedName("password")
+ public String password;
+
+ @SerializedName("enabled")
+ public Boolean enabled;
+
+ @SerializedName("accessed_at")
+ public String accessedAt;
+
+ @SerializedName("server")
+ public String server;
+
+ @SerializedName("port")
+ public int port;
+
+ @SerializedName("domain_id")
+ public String domainId;
+}
diff --git a/src/main/java/com/mailersend/sdk/smtpusers/SmtpUserBuilder.java b/src/main/java/com/mailersend/sdk/smtpusers/SmtpUserBuilder.java
new file mode 100644
index 0000000..a9719fd
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/smtpusers/SmtpUserBuilder.java
@@ -0,0 +1,129 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.smtpusers;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.mailersend.sdk.MailerSend;
+import com.mailersend.sdk.MailerSendApi;
+import com.mailersend.sdk.exceptions.MailerSendException;
+import com.mailersend.sdk.util.JsonSerializationDeserializationStrategy;
+
+/**
+ * SmtpUserBuilder class.
+ *
+ * @author mailersend
+ * @version $Id: $Id
+ */
+public class SmtpUserBuilder {
+
+ private MailerSend apiObjectReference;
+
+ private SmtpUserRequestBody body;
+
+
+ /**
+ * No instantiation from outside the SDK
+ *
+ * @param apiObjectRef a {@link com.mailersend.sdk.MailerSend} object.
+ */
+ protected SmtpUserBuilder(MailerSend apiObjectRef) {
+
+ apiObjectReference = apiObjectRef;
+ body = new SmtpUserRequestBody();
+ }
+
+
+ /**
+ * Set the name of the SMTP user
+ *
+ * @param name a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.smtpusers.SmtpUserBuilder} object.
+ */
+ public SmtpUserBuilder name(String name) {
+
+ body.name = name;
+
+ return this;
+ }
+
+
+ /**
+ * Set whether the SMTP user is enabled
+ *
+ * @param enabled a boolean.
+ * @return a {@link com.mailersend.sdk.smtpusers.SmtpUserBuilder} object.
+ */
+ public SmtpUserBuilder enabled(boolean enabled) {
+
+ body.enabled = enabled;
+
+ return this;
+ }
+
+
+ /**
+ * Creates a new SMTP user for the given domain
+ *
+ * @param domainId a {@link java.lang.String} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.smtpusers.SmtpUser} object.
+ */
+ public SmtpUser createSmtpUser(String domainId) throws MailerSendException {
+
+ String endpoint = "/domains/".concat(domainId).concat("/smtp-users");
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ Gson gson = new GsonBuilder()
+ .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false))
+ .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true))
+ .create();
+
+ String json = gson.toJson(body);
+
+ // reset the body object's values so that it can be reused
+ body.reset();
+
+ SingleSmtpUserResponse response = api.postRequest(endpoint, json, SingleSmtpUserResponse.class);
+
+ return response.smtpUser;
+ }
+
+
+ /**
+ * Updates an existing SMTP user
+ *
+ * @param domainId a {@link java.lang.String} object.
+ * @param smtpUserId a {@link java.lang.String} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.smtpusers.SmtpUser} object.
+ */
+ public SmtpUser updateSmtpUser(String domainId, String smtpUserId) throws MailerSendException {
+
+ String endpoint = "/domains/".concat(domainId).concat("/smtp-users/").concat(smtpUserId);
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ Gson gson = new GsonBuilder()
+ .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false))
+ .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true))
+ .create();
+
+ String json = gson.toJson(body);
+
+ // reset the body object's values so that it can be reused
+ body.reset();
+
+ SingleSmtpUserResponse response = api.putRequest(endpoint, json, SingleSmtpUserResponse.class);
+
+ return response.smtpUser;
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/smtpusers/SmtpUserRequestBody.java b/src/main/java/com/mailersend/sdk/smtpusers/SmtpUserRequestBody.java
new file mode 100644
index 0000000..2854d02
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/smtpusers/SmtpUserRequestBody.java
@@ -0,0 +1,33 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.smtpusers;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * SmtpUserRequestBody class.
+ *
+ * @author mailersend
+ * @version $Id: $Id
+ */
+public class SmtpUserRequestBody {
+
+ @SerializedName("name")
+ public String name;
+
+ @SerializedName("enabled")
+ public Boolean enabled;
+
+ /**
+ * Resets the body values so that the builder can be reused
+ */
+ protected void reset() {
+ name = null;
+ enabled = null;
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/smtpusers/SmtpUsers.java b/src/main/java/com/mailersend/sdk/smtpusers/SmtpUsers.java
new file mode 100644
index 0000000..f6fbfc9
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/smtpusers/SmtpUsers.java
@@ -0,0 +1,174 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.smtpusers;
+
+import java.util.ArrayList;
+import java.util.stream.IntStream;
+
+import com.mailersend.sdk.MailerSend;
+import com.mailersend.sdk.MailerSendApi;
+import com.mailersend.sdk.MailerSendResponse;
+import com.mailersend.sdk.exceptions.MailerSendException;
+
+/**
+ * SmtpUsers class.
+ *
+ * @author mailersend
+ * @version $Id: $Id
+ */
+public class SmtpUsers {
+
+ private MailerSend apiObjectReference;
+
+ private int pageFilter = 1;
+ private int limitFilter = 25;
+
+ private SmtpUserBuilder smtpUserBuilder;
+
+
+ /**
+ * Do not initialize directly. This should only be accessed from MailerSend.smtpUsers
+ *
+ * @param ref a {@link com.mailersend.sdk.MailerSend} object.
+ */
+ public SmtpUsers(MailerSend ref) {
+
+ apiObjectReference = ref;
+ smtpUserBuilder = new SmtpUserBuilder(ref);
+ }
+
+
+ /**
+ * Get the SMTP user builder
+ *
+ * @return a {@link com.mailersend.sdk.smtpusers.SmtpUserBuilder} object.
+ */
+ public SmtpUserBuilder smtpUserBuilder() {
+
+ return smtpUserBuilder;
+ }
+
+
+ /**
+ * Set the page of the request
+ *
+ * @param page a int.
+ * @return a {@link com.mailersend.sdk.smtpusers.SmtpUsers} object.
+ */
+ public SmtpUsers page(int page) {
+
+ pageFilter = page;
+
+ return this;
+ }
+
+
+ /**
+ * Set the results limit (10 - 100)
+ *
+ * @param limit a int.
+ * @return a {@link com.mailersend.sdk.smtpusers.SmtpUsers} object.
+ */
+ public SmtpUsers limit(int limit) {
+
+ limitFilter = limit;
+
+ return this;
+ }
+
+
+ /**
+ * Gets a list of SMTP users for the given domain
+ *
+ * @param domainId a {@link java.lang.String} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.smtpusers.SmtpUsersList} object.
+ */
+ public SmtpUsersList getSmtpUsers(String domainId) throws MailerSendException {
+
+ String endpoint = "/domains/".concat(domainId).concat("/smtp-users").concat(prepareParamsUrl());
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ SmtpUsersList response = api.getRequest(endpoint, SmtpUsersList.class);
+
+ return response;
+ }
+
+
+ /**
+ * Gets a single SMTP user
+ *
+ * @param domainId a {@link java.lang.String} object.
+ * @param smtpUserId a {@link java.lang.String} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.smtpusers.SmtpUser} object.
+ */
+ public SmtpUser getSmtpUser(String domainId, String smtpUserId) throws MailerSendException {
+
+ String endpoint = "/domains/".concat(domainId).concat("/smtp-users/").concat(smtpUserId);
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ SingleSmtpUserResponse response = api.getRequest(endpoint, SingleSmtpUserResponse.class);
+
+ return response.smtpUser;
+ }
+
+
+ /**
+ * Deletes an SMTP user
+ *
+ * @param domainId a {@link java.lang.String} object.
+ * @param smtpUserId a {@link java.lang.String} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a boolean.
+ */
+ public boolean deleteSmtpUser(String domainId, String smtpUserId) throws MailerSendException {
+
+ String endpoint = "/domains/".concat(domainId).concat("/smtp-users/").concat(smtpUserId);
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ MailerSendResponse response = api.deleteRequest(endpoint, MailerSendResponse.class);
+
+ // return true if the response is 200, 204 or 202
+ return IntStream.of(new int[] {200, 204, 202}).anyMatch(x -> x == response.responseStatusCode);
+ }
+
+
+ /**
+ * Prepares the query part of the request url
+ * @return
+ */
+ private String prepareParamsUrl() {
+
+ ArrayList params = new ArrayList();
+
+ params.add("page=".concat(String.valueOf(pageFilter)));
+ params.add("limit=".concat(String.valueOf(limitFilter)));
+
+ String requestParams = "";
+ for (int i = 0; i < params.size(); i++) {
+
+ String attrSep = "&";
+
+ if (i == 0) {
+
+ attrSep = "?";
+ }
+
+ requestParams = requestParams.concat(attrSep).concat(params.get(i));
+ }
+
+ return requestParams;
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/smtpusers/SmtpUsersList.java b/src/main/java/com/mailersend/sdk/smtpusers/SmtpUsersList.java
new file mode 100644
index 0000000..2d656ac
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/smtpusers/SmtpUsersList.java
@@ -0,0 +1,23 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.smtpusers;
+
+import com.google.gson.annotations.SerializedName;
+import com.mailersend.sdk.MailerSendResponse;
+
+/**
+ * SmtpUsersList class.
+ *
+ * @author mailersend
+ * @version $Id: $Id
+ */
+public class SmtpUsersList extends MailerSendResponse {
+
+ @SerializedName("data")
+ public SmtpUser[] smtpUsers;
+}
diff --git a/src/main/java/com/mailersend/sdk/templates/Template.java b/src/main/java/com/mailersend/sdk/templates/Template.java
index f49d45f..2eca098 100644
--- a/src/main/java/com/mailersend/sdk/templates/Template.java
+++ b/src/main/java/com/mailersend/sdk/templates/Template.java
@@ -7,6 +7,12 @@
**************************************************/
package com.mailersend.sdk.templates;
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.util.Date;
+import java.util.Map;
+
import com.google.gson.annotations.SerializedName;
/**
@@ -28,7 +34,26 @@ public class Template {
@SerializedName("image_path")
public String imagePath;
-
+
+ @SerializedName("description")
+ public String description;
+
+ @SerializedName("tags")
+ public String[] tags;
+
+ @SerializedName("variables")
+ public Map variables;
+
+ public Date createdAt;
+
+ @SerializedName("created_at")
+ private String createdAtStr;
+
+ public Date updatedAt;
+
+ @SerializedName("updated_at")
+ private String updatedAtStr;
+
@SerializedName("category")
public TemplateCategory category;
@@ -44,15 +69,42 @@ public class Template {
* Do not call directly
*/
protected void postDeserialize() {
-
+
+ parseDates();
+
if (domain != null) {
-
+
domain.postDeserialize();
}
-
+
if (stats != null) {
-
+
stats.postDeserialize();
}
}
+
+
+ /**
+ * Parses the string dates from the response into java.util.Date objects
+ */
+ protected void parseDates() {
+
+ TemporalAccessor ta;
+ Instant instant;
+
+ if (createdAtStr != null && !createdAtStr.isBlank()) {
+
+ ta = DateTimeFormatter.ISO_INSTANT.parse(createdAtStr);
+ instant = Instant.from(ta);
+ createdAt = Date.from(instant);
+ }
+
+ if (updatedAtStr != null && !updatedAtStr.isBlank()) {
+
+ ta = DateTimeFormatter.ISO_INSTANT.parse(updatedAtStr);
+ instant = Instant.from(ta);
+ updatedAt = Date.from(instant);
+ }
+
+ }
}
diff --git a/src/main/java/com/mailersend/sdk/templates/TemplateBuilder.java b/src/main/java/com/mailersend/sdk/templates/TemplateBuilder.java
new file mode 100644
index 0000000..4712277
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/templates/TemplateBuilder.java
@@ -0,0 +1,258 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.templates;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.mailersend.sdk.MailerSend;
+import com.mailersend.sdk.MailerSendApi;
+import com.mailersend.sdk.exceptions.MailerSendException;
+import com.mailersend.sdk.util.JsonSerializationDeserializationStrategy;
+
+/**
+ * TemplateBuilder class.
+ *
+ * @author mailersend
+ * @version $Id: $Id
+ */
+public class TemplateBuilder {
+
+ private MailerSend apiObjectReference;
+
+ private TemplateBuilderBody builderBody;
+
+
+ /**
+ * No instantiation from outside the sdk.
+ *
+ * @param ref a {@link com.mailersend.sdk.MailerSend} object.
+ */
+ protected TemplateBuilder(MailerSend ref) {
+
+ apiObjectReference = ref;
+ builderBody = new TemplateBuilderBody();
+ }
+
+
+ /**
+ * Set the template name (max 50 characters).
+ *
+ * @param name a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.templates.TemplateBuilder} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException if the name exceeds 50 characters.
+ */
+ public TemplateBuilder name(String name) throws MailerSendException {
+
+ if (name != null && name.length() > 50) {
+
+ throw new MailerSendException("Template name cannot be longer than 50 characters");
+ }
+
+ builderBody.name = name;
+
+ return this;
+ }
+
+
+ /**
+ * Set the HTML body of the template.
+ *
+ * @param html a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.templates.TemplateBuilder} object.
+ */
+ public TemplateBuilder html(String html) {
+
+ builderBody.html = html;
+
+ return this;
+ }
+
+
+ /**
+ * Set the plain text version of the template.
+ *
+ * @param text a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.templates.TemplateBuilder} object.
+ */
+ public TemplateBuilder text(String text) {
+
+ builderBody.text = text;
+
+ return this;
+ }
+
+
+ /**
+ * Set the subject of the template.
+ *
+ * @param subject a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.templates.TemplateBuilder} object.
+ */
+ public TemplateBuilder subject(String subject) {
+
+ builderBody.subject = subject;
+
+ return this;
+ }
+
+
+ /**
+ * Set the domain ID to associate with the template.
+ *
+ * @param domainId a {@link java.lang.String} object.
+ * @return a {@link com.mailersend.sdk.templates.TemplateBuilder} object.
+ */
+ public TemplateBuilder domainId(String domainId) {
+
+ builderBody.domainId = domainId;
+
+ return this;
+ }
+
+
+ /**
+ * Set the category IDs to associate with the template.
+ *
+ * @param categories an array of category ID strings.
+ * @return a {@link com.mailersend.sdk.templates.TemplateBuilder} object.
+ */
+ public TemplateBuilder categories(String[] categories) {
+
+ builderBody.categories = categories;
+
+ return this;
+ }
+
+
+ /**
+ * Set the tags for the template (max 5 items, each max 191 chars).
+ *
+ * @param tags an array of tag strings.
+ * @return a {@link com.mailersend.sdk.templates.TemplateBuilder} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException if tags exceed 5 items or any tag exceeds 191 characters.
+ */
+ public TemplateBuilder tags(String[] tags) throws MailerSendException {
+
+ if (tags != null && tags.length > 5) {
+
+ throw new MailerSendException("Template tags cannot have more than 5 items");
+ }
+
+ if (tags != null) {
+
+ for (String tag : tags) {
+
+ if (tag.length() > 191) {
+
+ throw new MailerSendException("Each template tag cannot be longer than 191 characters");
+ }
+ }
+ }
+
+ builderBody.tags = tags;
+
+ return this;
+ }
+
+
+ /**
+ * Set whether plain text should be auto-generated from the HTML.
+ *
+ * @param autoGenerate a boolean.
+ * @return a {@link com.mailersend.sdk.templates.TemplateBuilder} object.
+ */
+ public TemplateBuilder autoGenerate(boolean autoGenerate) {
+
+ builderBody.autoGenerate = autoGenerate;
+
+ return this;
+ }
+
+
+ /**
+ * Creates a new template via POST /v1/templates.
+ *
+ * @throws com.mailersend.sdk.exceptions.MailerSendException if any.
+ * @return a {@link com.mailersend.sdk.templates.Template} object.
+ */
+ public Template createTemplate() throws MailerSendException {
+
+ if (builderBody.html == null || builderBody.html.isBlank()) {
+
+ throw new MailerSendException("Template html cannot be empty");
+ }
+
+ if (builderBody.text == null || builderBody.text.isBlank()) {
+
+ throw new MailerSendException("Template text cannot be empty");
+ }
+
+ String endpoint = "/templates";
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ Gson gson = new GsonBuilder()
+ .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false))
+ .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true))
+ .create();
+
+ String json = gson.toJson(builderBody);
+
+ builderBody.reset();
+
+ TemplateResponse response = api.postRequest(endpoint, json, TemplateResponse.class);
+
+ if (response.template != null) {
+
+ response.template.postDeserialize();
+ }
+
+ return response.template;
+ }
+
+
+ /**
+ * Updates an existing template via PUT /v1/templates/{templateId}.
+ * Only templates created via API (origin=api) can be updated.
+ *
+ * @param templateId a {@link java.lang.String} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException if any.
+ * @return a {@link com.mailersend.sdk.templates.Template} object.
+ */
+ public Template updateTemplate(String templateId) throws MailerSendException {
+
+ if (templateId == null || templateId.isBlank()) {
+
+ throw new MailerSendException("Template ID cannot be empty");
+ }
+
+ String endpoint = "/templates/" + templateId;
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ Gson gson = new GsonBuilder()
+ .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false))
+ .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true))
+ .create();
+
+ String json = gson.toJson(builderBody);
+
+ builderBody.reset();
+
+ TemplateResponse response = api.putRequest(endpoint, json, TemplateResponse.class);
+
+ if (response.template != null) {
+
+ response.template.postDeserialize();
+ }
+
+ return response.template;
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/templates/TemplateBuilderBody.java b/src/main/java/com/mailersend/sdk/templates/TemplateBuilderBody.java
new file mode 100644
index 0000000..fa585e1
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/templates/TemplateBuilderBody.java
@@ -0,0 +1,57 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.templates;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Used by the template builder to prepare the API request body.
+ * Do not use directly.
+ */
+class TemplateBuilderBody {
+
+ @SerializedName("name")
+ public String name;
+
+ @SerializedName("html")
+ public String html;
+
+ @SerializedName("text")
+ public String text;
+
+ @SerializedName("subject")
+ public String subject;
+
+ @SerializedName("domain_id")
+ public String domainId;
+
+ @SerializedName("categories")
+ public String[] categories;
+
+ @SerializedName("tags")
+ public String[] tags;
+
+ @SerializedName("auto_generate")
+ public Boolean autoGenerate;
+
+
+ /**
+ * reset.
+ */
+ public void reset() {
+
+ name = null;
+ html = null;
+ text = null;
+ subject = null;
+ domainId = null;
+ categories = null;
+ tags = null;
+ autoGenerate = null;
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/templates/TemplateItem.java b/src/main/java/com/mailersend/sdk/templates/TemplateItem.java
index a2dcde3..621416f 100644
--- a/src/main/java/com/mailersend/sdk/templates/TemplateItem.java
+++ b/src/main/java/com/mailersend/sdk/templates/TemplateItem.java
@@ -11,6 +11,7 @@
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
+import java.util.Map;
import com.google.gson.annotations.SerializedName;
@@ -33,11 +34,25 @@ public class TemplateItem {
@SerializedName("image_path")
public String imagePath;
-
+
+ @SerializedName("description")
+ public String description;
+
+ @SerializedName("tags")
+ public String[] tags;
+
+ @SerializedName("variables")
+ public Map variables;
+
public Date createdAt;
-
+
@SerializedName("created_at")
private String createdAtStr;
+
+ public Date updatedAt;
+
+ @SerializedName("updated_at")
+ private String updatedAtStr;
/**
@@ -59,11 +74,18 @@ protected void parseDates() {
Instant instant;
if (createdAtStr != null && !createdAtStr.isBlank()) {
-
+
ta = DateTimeFormatter.ISO_INSTANT.parse(createdAtStr);
instant = Instant.from(ta);
createdAt = Date.from(instant);
}
-
+
+ if (updatedAtStr != null && !updatedAtStr.isBlank()) {
+
+ ta = DateTimeFormatter.ISO_INSTANT.parse(updatedAtStr);
+ instant = Instant.from(ta);
+ updatedAt = Date.from(instant);
+ }
+
}
}
diff --git a/src/main/java/com/mailersend/sdk/templates/Templates.java b/src/main/java/com/mailersend/sdk/templates/Templates.java
index cea6cb5..31904e9 100644
--- a/src/main/java/com/mailersend/sdk/templates/Templates.java
+++ b/src/main/java/com/mailersend/sdk/templates/Templates.java
@@ -23,7 +23,9 @@
public class Templates {
private MailerSend apiObjectReference;
-
+
+ private TemplateBuilder templateBuilder;
+
private int pageFilter = 1;
private int limitFilter = 25;
private String domainIdFilter = null;
@@ -35,35 +37,59 @@ public class Templates {
* @param ref a {@link com.mailersend.sdk.MailerSend} object.
*/
public Templates(MailerSend ref) {
-
+
apiObjectReference = ref;
+ templateBuilder = new TemplateBuilder(ref);
}
+ /**
+ * Returns a new TemplateBuilder for creating or updating templates.
+ *
+ * @return a {@link com.mailersend.sdk.templates.TemplateBuilder} object.
+ */
+ public TemplateBuilder builder() {
+
+ return templateBuilder;
+ }
+
+
/**
* Set the page of the request
*
* @param page a int.
* @return a {@link com.mailersend.sdk.templates.Templates} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException if page is less than 1.
*/
- public Templates page(int page) {
-
+ public Templates page(int page) throws MailerSendException {
+
+ if (page < 1) {
+
+ throw new MailerSendException("Page must be at least 1");
+ }
+
pageFilter = page;
-
+
return this;
}
-
-
+
+
/**
* Set the results limit (10 - 100)
*
* @param limit a int.
* @return a {@link com.mailersend.sdk.templates.Templates} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException if limit is not between 10 and 100.
*/
- public Templates limit(int limit) {
-
+ public Templates limit(int limit) throws MailerSendException {
+
+ if (limit < 10 || limit > 100) {
+
+ throw new MailerSendException("Limit must be between 10 and 100");
+ }
+
limitFilter = limit;
-
+
return this;
}
@@ -111,7 +137,12 @@ public TemplatesList getTemplates() throws MailerSendException {
* @return a {@link com.mailersend.sdk.templates.Template} object.
*/
public Template getTemplate(String templateId) throws MailerSendException {
-
+
+ if (templateId == null || templateId.isBlank()) {
+
+ throw new MailerSendException("Template ID cannot be empty");
+ }
+
String endpoint = "/templates/".concat(templateId);
MailerSendApi api = new MailerSendApi();
@@ -136,7 +167,12 @@ public Template getTemplate(String templateId) throws MailerSendException {
* @return a {@link com.mailersend.sdk.MailerSendResponse} object.
*/
public MailerSendResponse deleteTemplate(String templateId) throws MailerSendException {
-
+
+ if (templateId == null || templateId.isBlank()) {
+
+ throw new MailerSendException("Template ID cannot be empty");
+ }
+
String endpoint = "/templates/".concat(templateId);
MailerSendApi api = new MailerSendApi();
diff --git a/src/main/java/com/mailersend/sdk/tokens/Token.java b/src/main/java/com/mailersend/sdk/tokens/Token.java
index 2880533..0600d5b 100644
--- a/src/main/java/com/mailersend/sdk/tokens/Token.java
+++ b/src/main/java/com/mailersend/sdk/tokens/Token.java
@@ -30,7 +30,10 @@ public class Token {
@SerializedName("status")
public String status;
-
+
+ @SerializedName("scopes")
+ public String[] scopes;
+
@SerializedName("created_at")
private String createdAtStr;
diff --git a/src/main/java/com/mailersend/sdk/tokens/TokenAdd.java b/src/main/java/com/mailersend/sdk/tokens/TokenAdd.java
index c34f57e..7b1e14f 100644
--- a/src/main/java/com/mailersend/sdk/tokens/TokenAdd.java
+++ b/src/main/java/com/mailersend/sdk/tokens/TokenAdd.java
@@ -31,7 +31,13 @@ public class TokenAdd {
@SerializedName("name")
public String name;
-
+
+ @SerializedName("scopes")
+ public String[] scopes;
+
+ @SerializedName("domain")
+ public TokenDomain domain;
+
@SerializedName("created_at")
private String createdAtStr;
diff --git a/src/main/java/com/mailersend/sdk/tokens/TokenAddBuilder.java b/src/main/java/com/mailersend/sdk/tokens/TokenAddBuilder.java
index d304d73..bfe831f 100644
--- a/src/main/java/com/mailersend/sdk/tokens/TokenAddBuilder.java
+++ b/src/main/java/com/mailersend/sdk/tokens/TokenAddBuilder.java
@@ -39,7 +39,27 @@ public class TokenAddBuilder {
"analytics_full",
"tokens_full",
"webhooks_full",
- "templates_full"
+ "templates_full",
+ "suppressions_read",
+ "suppressions_full",
+ "sms_read",
+ "sms_full",
+ "email_verification_read",
+ "email_verification_full",
+ "inbounds_full",
+ "recipients_read",
+ "recipients_full",
+ "sender_identity_read",
+ "sender_identity_full",
+ "users_read",
+ "users_full",
+ "smtp_users_read",
+ "smtp_users_full",
+ "dmarc_monitoring_read",
+ "dmarc_monitoring_full",
+ "blocklist_monitoring_read",
+ "blocklist_monitoring_full",
+ "whatsapp_full"
};
/**
@@ -111,15 +131,15 @@ public TokenAddBuilder addScope(String scope) throws MailerSendException {
public TokenAdd addToken() throws MailerSendException {
if (tokenAddBody.name == null || tokenAddBody.name.isBlank()) {
-
+
throw new MailerSendException("Token name cannot be null or empty");
}
-
- if (tokenAddBody.domainId == null || tokenAddBody.domainId.isBlank()) {
-
- throw new MailerSendException("Domain ID cannot be null or empty");
+
+ if (tokenAddBody.name.length() > 50) {
+
+ throw new MailerSendException("Token name cannot be longer than 50 characters");
}
-
+
if (tokenAddBody.scopes.size() == 0) {
throw new MailerSendException("At least one scope is required");
diff --git a/src/main/java/com/mailersend/sdk/tokens/TokenDomain.java b/src/main/java/com/mailersend/sdk/tokens/TokenDomain.java
new file mode 100644
index 0000000..a5d9992
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/tokens/TokenDomain.java
@@ -0,0 +1,24 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.tokens;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Represents the domain object returned as part of a token creation response.
+ *
+ * @author mailersend
+ */
+public class TokenDomain {
+
+ @SerializedName("id")
+ public String id;
+
+ @SerializedName("name")
+ public String name;
+}
diff --git a/src/main/java/com/mailersend/sdk/tokens/TokenListResponse.java b/src/main/java/com/mailersend/sdk/tokens/TokenListResponse.java
new file mode 100644
index 0000000..e7e2334
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/tokens/TokenListResponse.java
@@ -0,0 +1,23 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.tokens;
+
+import com.google.gson.annotations.SerializedName;
+import com.mailersend.sdk.MailerSendResponse;
+
+/**
+ * TokenListResponse class.
+ *
+ * @author mailersend
+ * @version $Id: $Id
+ */
+public class TokenListResponse extends MailerSendResponse {
+
+ @SerializedName("data")
+ public Token[] tokens;
+}
diff --git a/src/main/java/com/mailersend/sdk/tokens/TokenScopes.java b/src/main/java/com/mailersend/sdk/tokens/TokenScopes.java
index e01f81c..1e4ac61 100644
--- a/src/main/java/com/mailersend/sdk/tokens/TokenScopes.java
+++ b/src/main/java/com/mailersend/sdk/tokens/TokenScopes.java
@@ -1,7 +1,7 @@
/*************************************************
* MailerSend Java SDK
* https://github.com/mailersend/mailersend-java
- *
+ *
* @author MailerSend
* https://mailersend.com
**************************************************/
@@ -17,31 +17,91 @@ public class TokenScopes {
/** Constant emailFull="email_full" */
public static final String emailFull = "email_full";
-
+
/** Constant domainsRead="domains_read" */
public static final String domainsRead = "domains_read";
-
+
/** Constant domainsFull="domains_full" */
public static final String domainsFull = "domains_full";
-
+
/** Constant activityRead="activity_read" */
public static final String activityRead = "activity_read";
-
+
/** Constant activityFull="activity_full" */
public static final String activityFull = "activity_full";
-
+
/** Constant analyticsRead="analytics_read" */
public static final String analyticsRead = "analytics_read";
-
+
/** Constant analyticsFull="analytics_full" */
public static final String analyticsFull = "analytics_full";
-
+
/** Constant tokensFull="tokens_full" */
public static final String tokensFull = "tokens_full";
-
+
/** Constant webhooksFull="webhooks_full" */
public static final String webhooksFull = "webhooks_full";
-
+
/** Constant templatesFull="templates_full" */
public static final String templatesFull = "templates_full";
+
+ /** Constant suppressionsRead="suppressions_read" */
+ public static final String suppressionsRead = "suppressions_read";
+
+ /** Constant suppressionsFull="suppressions_full" */
+ public static final String suppressionsFull = "suppressions_full";
+
+ /** Constant smsRead="sms_read" */
+ public static final String smsRead = "sms_read";
+
+ /** Constant smsFull="sms_full" */
+ public static final String smsFull = "sms_full";
+
+ /** Constant emailVerificationRead="email_verification_read" */
+ public static final String emailVerificationRead = "email_verification_read";
+
+ /** Constant emailVerificationFull="email_verification_full" */
+ public static final String emailVerificationFull = "email_verification_full";
+
+ /** Constant inboundsFull="inbounds_full" */
+ public static final String inboundsFull = "inbounds_full";
+
+ /** Constant recipientsRead="recipients_read" */
+ public static final String recipientsRead = "recipients_read";
+
+ /** Constant recipientsFull="recipients_full" */
+ public static final String recipientsFull = "recipients_full";
+
+ /** Constant senderIdentityRead="sender_identity_read" */
+ public static final String senderIdentityRead = "sender_identity_read";
+
+ /** Constant senderIdentityFull="sender_identity_full" */
+ public static final String senderIdentityFull = "sender_identity_full";
+
+ /** Constant usersRead="users_read" */
+ public static final String usersRead = "users_read";
+
+ /** Constant usersFull="users_full" */
+ public static final String usersFull = "users_full";
+
+ /** Constant smtpUsersRead="smtp_users_read" */
+ public static final String smtpUsersRead = "smtp_users_read";
+
+ /** Constant smtpUsersFull="smtp_users_full" */
+ public static final String smtpUsersFull = "smtp_users_full";
+
+ /** Constant dmarcMonitoringRead="dmarc_monitoring_read" */
+ public static final String dmarcMonitoringRead = "dmarc_monitoring_read";
+
+ /** Constant dmarcMonitoringFull="dmarc_monitoring_full" */
+ public static final String dmarcMonitoringFull = "dmarc_monitoring_full";
+
+ /** Constant blocklistMonitoringRead="blocklist_monitoring_read" */
+ public static final String blocklistMonitoringRead = "blocklist_monitoring_read";
+
+ /** Constant blocklistMonitoringFull="blocklist_monitoring_full" */
+ public static final String blocklistMonitoringFull = "blocklist_monitoring_full";
+
+ /** Constant whatsappFull="whatsapp_full" */
+ public static final String whatsappFull = "whatsapp_full";
}
diff --git a/src/main/java/com/mailersend/sdk/tokens/Tokens.java b/src/main/java/com/mailersend/sdk/tokens/Tokens.java
index 42098a0..020b7f4 100644
--- a/src/main/java/com/mailersend/sdk/tokens/Tokens.java
+++ b/src/main/java/com/mailersend/sdk/tokens/Tokens.java
@@ -1,12 +1,14 @@
/*************************************************
* MailerSend Java SDK
* https://github.com/mailersend/mailersend-java
- *
+ *
* @author MailerSend
* https://mailersend.com
**************************************************/
package com.mailersend.sdk.tokens;
+import java.util.ArrayList;
+
import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.MailerSendApi;
import com.mailersend.sdk.MailerSendResponse;
@@ -21,33 +23,109 @@
public class Tokens {
private MailerSend apiObjectReference;
-
+
private TokenAddBuilder addTokenBuilder;
-
+
+ private int pageFilter = 1;
+ private int limitFilter = 25;
+
/**
* Constructor for Tokens.
*
* @param ref a {@link com.mailersend.sdk.MailerSend} object.
*/
public Tokens(MailerSend ref) {
-
+
apiObjectReference = ref;
-
+
addTokenBuilder = new TokenAddBuilder(ref);
}
-
-
+
+
/**
* Returns the add token builder
*
* @return a {@link com.mailersend.sdk.tokens.TokenAddBuilder} object.
*/
public TokenAddBuilder addBuilder() {
-
+
return addTokenBuilder;
}
-
-
+
+
+ /**
+ * Set the page for list requests
+ *
+ * @param page a int.
+ * @return a {@link com.mailersend.sdk.tokens.Tokens} object.
+ */
+ public Tokens page(int page) {
+
+ pageFilter = page;
+
+ return this;
+ }
+
+
+ /**
+ * Set the results limit for list requests (10 - 100)
+ *
+ * @param limit a int.
+ * @return a {@link com.mailersend.sdk.tokens.Tokens} object.
+ */
+ public Tokens limit(int limit) {
+
+ limitFilter = limit;
+
+ return this;
+ }
+
+
+ /**
+ * Retrieves a list of API tokens
+ *
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.tokens.TokenListResponse} object.
+ */
+ public TokenListResponse getTokens() throws MailerSendException {
+
+ String endpoint = "/token".concat(prepareParamsUrl());
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ TokenListResponse response = api.getRequest(endpoint, TokenListResponse.class);
+
+ for (Token token : response.tokens) {
+ token.postDeserialize();
+ }
+
+ return response;
+ }
+
+
+ /**
+ * Retrieves a single API token by its ID
+ *
+ * @param tokenId a {@link java.lang.String} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.tokens.Token} object.
+ */
+ public Token getToken(String tokenId) throws MailerSendException {
+
+ String endpoint = "/token/".concat(tokenId);
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ TokenResponse response = api.getRequest(endpoint, TokenResponse.class);
+
+ response.token.postDeserialize();
+
+ return response.token;
+ }
+
+
/**
* Updates a token's status
*
@@ -57,28 +135,67 @@ public TokenAddBuilder addBuilder() {
* @return a {@link com.mailersend.sdk.tokens.Token} object.
*/
public Token updateToken(String tokenId, boolean paused) throws MailerSendException {
-
- String endpoint = "/token/".concat(tokenId).concat("/settings");
-
+
+ String endpoint = "/token/".concat(tokenId);
+
MailerSendApi api = new MailerSendApi();
api.setToken(apiObjectReference.getToken());
-
- String json = "{\"status\":\"pause\"}";
-
- if (!paused) {
-
- json = "{\"status\":\"unpause\"}";
+
+ String status = paused ? "pause" : "unpause";
+ String json = "{\"status\":\"" + status + "\"}";
+
+ TokenResponse response = api.putRequest(endpoint, json, TokenResponse.class);
+
+ response.token.postDeserialize();
+
+ return response.token;
+ }
+
+
+ /**
+ * Updates a token's name and/or status
+ *
+ * @param tokenId a {@link java.lang.String} object.
+ * @param name a {@link java.lang.String} object, or null to leave unchanged.
+ * @param status a {@link java.lang.String} object ("pause" or "unpause"), or null to leave unchanged.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link com.mailersend.sdk.tokens.Token} object.
+ */
+ public Token updateToken(String tokenId, String name, String status) throws MailerSendException {
+
+ boolean nameBlank = (name == null || name.isBlank());
+ boolean statusBlank = (status == null || status.isBlank());
+
+ if (nameBlank && statusBlank) {
+
+ throw new MailerSendException("At least one of name or status must be provided");
}
-
-
+
+ String endpoint = "/token/".concat(tokenId);
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ ArrayList fields = new ArrayList();
+
+ if (name != null && !name.isBlank()) {
+ fields.add("\"name\":\"" + name + "\"");
+ }
+
+ if (status != null && !status.isBlank()) {
+ fields.add("\"status\":\"" + status + "\"");
+ }
+
+ String json = "{" + String.join(",", fields) + "}";
+
TokenResponse response = api.putRequest(endpoint, json, TokenResponse.class);
-
+
response.token.postDeserialize();
-
+
return response.token;
}
-
-
+
+
/**
* Deletes a token
*
@@ -87,15 +204,38 @@ public Token updateToken(String tokenId, boolean paused) throws MailerSendExcept
* @return a {@link com.mailersend.sdk.MailerSendResponse} object.
*/
public MailerSendResponse deleteToken(String tokenId) throws MailerSendException {
-
+
String endpoint = "/token/".concat(tokenId);
-
+
MailerSendApi api = new MailerSendApi();
api.setToken(apiObjectReference.getToken());
-
+
MailerSendResponse response = api.deleteRequest(endpoint, MailerSendResponse.class);
-
+
return response;
}
-
+
+
+ /**
+ * Prepares the query part of the request url
+ *
+ * @return a {@link java.lang.String} object.
+ */
+ private String prepareParamsUrl() {
+
+ ArrayList params = new ArrayList();
+
+ params.add("page=".concat(String.valueOf(pageFilter)));
+ params.add("limit=".concat(String.valueOf(limitFilter)));
+
+ String requestParams = "";
+ for (int i = 0; i < params.size(); i++) {
+
+ String attrSep = i == 0 ? "?" : "&";
+ requestParams = requestParams.concat(attrSep).concat(params.get(i));
+ }
+
+ return requestParams;
+ }
+
}
diff --git a/src/main/java/com/mailersend/sdk/users/Invite.java b/src/main/java/com/mailersend/sdk/users/Invite.java
new file mode 100644
index 0000000..58406d6
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/users/Invite.java
@@ -0,0 +1,83 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.users;
+
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.util.Date;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Represents a pending user invite.
+ */
+public class Invite {
+
+ @SerializedName("id")
+ public String id;
+
+ @SerializedName("email")
+ public String email;
+
+ @SerializedName("data")
+ public InviteData data;
+
+ @SerializedName("role")
+ public String role;
+
+ @SerializedName("permissions")
+ public String[] permissions;
+
+ @SerializedName("requires_periodic_password_change")
+ public boolean requiresPeriodicPasswordChange;
+
+ public Date createdAt;
+
+ @SerializedName("created_at")
+ private String createdAtStr;
+
+ public Date updatedAt;
+
+ @SerializedName("updated_at")
+ private String updatedAtStr;
+
+
+ /**
+ * Is called to perform any actions after the deserialization of the response.
+ * Do not call directly.
+ */
+ protected void postDeserialize() {
+
+ parseDates();
+ }
+
+
+ /**
+ * Parses the string dates from the response into java.util.Date objects.
+ */
+ private void parseDates() {
+
+ TemporalAccessor ta;
+ Instant instant;
+
+ if (createdAtStr != null && !createdAtStr.isBlank()) {
+
+ ta = DateTimeFormatter.ISO_INSTANT.parse(createdAtStr);
+ instant = Instant.from(ta);
+ createdAt = Date.from(instant);
+ }
+
+ if (updatedAtStr != null && !updatedAtStr.isBlank()) {
+
+ ta = DateTimeFormatter.ISO_INSTANT.parse(updatedAtStr);
+ instant = Instant.from(ta);
+ updatedAt = Date.from(instant);
+ }
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/users/InviteData.java b/src/main/java/com/mailersend/sdk/users/InviteData.java
new file mode 100644
index 0000000..bceb9e1
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/users/InviteData.java
@@ -0,0 +1,23 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.users;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Represents the nested data object within an invite response,
+ * which contains domain and template ID arrays.
+ */
+public class InviteData {
+
+ @SerializedName("domains")
+ public String[] domains;
+
+ @SerializedName("templates")
+ public String[] templates;
+}
diff --git a/src/main/java/com/mailersend/sdk/users/InviteResponse.java b/src/main/java/com/mailersend/sdk/users/InviteResponse.java
new file mode 100644
index 0000000..910e000
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/users/InviteResponse.java
@@ -0,0 +1,20 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.users;
+
+import com.google.gson.annotations.SerializedName;
+import com.mailersend.sdk.MailerSendResponse;
+
+/**
+ * Wraps a single invite response from the API.
+ */
+public class InviteResponse extends MailerSendResponse {
+
+ @SerializedName("data")
+ public Invite invite;
+}
diff --git a/src/main/java/com/mailersend/sdk/users/InvitesList.java b/src/main/java/com/mailersend/sdk/users/InvitesList.java
new file mode 100644
index 0000000..3d8e192
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/users/InvitesList.java
@@ -0,0 +1,33 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.users;
+
+import com.google.gson.annotations.SerializedName;
+import com.mailersend.sdk.util.PaginatedResponse;
+
+/**
+ * Wraps a paginated list of invites from the API.
+ */
+public class InvitesList extends PaginatedResponse {
+
+ @SerializedName("data")
+ public Invite[] invites;
+
+
+ /**
+ * postDeserialize.
+ */
+ protected void postDeserialize() {
+
+ if (invites != null) {
+ for (Invite invite : invites) {
+ invite.postDeserialize();
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/users/User.java b/src/main/java/com/mailersend/sdk/users/User.java
new file mode 100644
index 0000000..731c6ef
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/users/User.java
@@ -0,0 +1,107 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.users;
+
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.util.Date;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Represents a MailerSend account user.
+ */
+public class User {
+
+ @SerializedName("id")
+ public String id;
+
+ @SerializedName("avatar")
+ public String avatar;
+
+ @SerializedName("email")
+ public String email;
+
+ @SerializedName("last_name")
+ public String lastName;
+
+ @SerializedName("name")
+ public String name;
+
+ @SerializedName("2fa")
+ public boolean twoFactorAuth;
+
+ @SerializedName("role")
+ public String role;
+
+ @SerializedName("permissions")
+ public String[] permissions;
+
+ @SerializedName("domains")
+ public UserDomain[] domains;
+
+ @SerializedName("templates")
+ public UserTemplate[] templates;
+
+ public Date createdAt;
+
+ @SerializedName("created_at")
+ private String createdAtStr;
+
+ public Date updatedAt;
+
+ @SerializedName("updated_at")
+ private String updatedAtStr;
+
+
+ /**
+ * Is called to perform any actions after the deserialization of the response.
+ * Do not call directly.
+ */
+ protected void postDeserialize() {
+
+ parseDates();
+
+ if (domains != null) {
+ for (UserDomain domain : domains) {
+ domain.postDeserialize();
+ }
+ }
+
+ if (templates != null) {
+ for (UserTemplate template : templates) {
+ template.postDeserialize();
+ }
+ }
+ }
+
+
+ /**
+ * Parses the string dates from the response into java.util.Date objects.
+ */
+ private void parseDates() {
+
+ TemporalAccessor ta;
+ Instant instant;
+
+ if (createdAtStr != null && !createdAtStr.isBlank()) {
+
+ ta = DateTimeFormatter.ISO_INSTANT.parse(createdAtStr);
+ instant = Instant.from(ta);
+ createdAt = Date.from(instant);
+ }
+
+ if (updatedAtStr != null && !updatedAtStr.isBlank()) {
+
+ ta = DateTimeFormatter.ISO_INSTANT.parse(updatedAtStr);
+ instant = Instant.from(ta);
+ updatedAt = Date.from(instant);
+ }
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/users/UserBuilder.java b/src/main/java/com/mailersend/sdk/users/UserBuilder.java
new file mode 100644
index 0000000..66e3bb6
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/users/UserBuilder.java
@@ -0,0 +1,229 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.users;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.mailersend.sdk.MailerSend;
+import com.mailersend.sdk.MailerSendApi;
+import com.mailersend.sdk.exceptions.MailerSendException;
+import com.mailersend.sdk.util.JsonSerializationDeserializationStrategy;
+
+/**
+ * Builder for creating or updating account users (invites).
+ *
+ * Usage example — invite a new user:
+ *
+ * Invite invite = ms.users().builder()
+ * .email("user@example.com")
+ * .role("Admin")
+ * .inviteUser();
+ *
+ *
+ * Usage example — update an existing user:
+ *
+ * User user = ms.users().builder()
+ * .role("Manager")
+ * .updateUser("user-id");
+ *
+ */
+public class UserBuilder {
+
+ private final MailerSend apiObjectReference;
+
+ private final UserRequestBody builderBody = new UserRequestBody();
+
+
+ /**
+ * No instantiation from outside the SDK.
+ *
+ * @param apiObjectRef a {@link com.mailersend.sdk.MailerSend} object.
+ */
+ protected UserBuilder(MailerSend apiObjectRef) {
+
+ apiObjectReference = apiObjectRef;
+ }
+
+
+ /**
+ * Set the email address of the user to invite.
+ *
+ * @param email the email address
+ * @return this builder
+ */
+ public UserBuilder email(String email) {
+
+ builderBody.email = email;
+
+ return this;
+ }
+
+
+ /**
+ * Set the role of the user.
+ *
+ * Valid values: {@code Admin}, {@code Manager}, {@code Designer},
+ * {@code Accountant}, {@code Custom User}.
+ *
+ * @param role the role name
+ * @return this builder
+ */
+ public UserBuilder role(String role) {
+
+ builderBody.role = role;
+
+ return this;
+ }
+
+
+ /**
+ * Add a permission for the user (required when role is {@code Custom User}).
+ *
+ * @param permission the permission name (e.g. {@code "read-suppressions"})
+ * @return this builder
+ */
+ public UserBuilder addPermission(String permission) {
+
+ builderBody.permissions.add(permission);
+
+ return this;
+ }
+
+
+ /**
+ * Add a template ID to restrict the user's template access.
+ *
+ * @param templateId the template ID
+ * @return this builder
+ */
+ public UserBuilder addTemplate(String templateId) {
+
+ builderBody.templates.add(templateId);
+
+ return this;
+ }
+
+
+ /**
+ * Add a domain ID to restrict the user's domain access.
+ *
+ * @param domainId the domain ID
+ * @return this builder
+ */
+ public UserBuilder addDomain(String domainId) {
+
+ builderBody.domains.add(domainId);
+
+ return this;
+ }
+
+
+ /**
+ * Set whether the user is required to change their password periodically.
+ *
+ * @param required {@code true} to require periodic password changes
+ * @return this builder
+ */
+ public UserBuilder requiresPeriodicPasswordChange(boolean required) {
+
+ builderBody.requiresPeriodicPasswordChange = required;
+
+ return this;
+ }
+
+
+ /**
+ * Invites (creates) a new user in the account.
+ *
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return the created {@link Invite} object
+ */
+ public Invite inviteUser() throws MailerSendException {
+
+ if (builderBody.email == null || builderBody.email.isBlank()) {
+
+ throw new MailerSendException("User email cannot be null or empty");
+ }
+
+ if (builderBody.role == null || builderBody.role.isBlank()) {
+
+ throw new MailerSendException("User role cannot be null or empty");
+ }
+
+ if ("Custom User".equals(builderBody.role) && builderBody.permissions.isEmpty()) {
+
+ throw new MailerSendException("Permissions are required for Custom User role");
+ }
+
+ String endpoint = "/users";
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ Gson gson = new GsonBuilder()
+ .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false))
+ .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true))
+ .create();
+
+ String json = gson.toJson(builderBody);
+
+ builderBody.reset();
+
+ InviteResponse response = api.postRequest(endpoint, json, InviteResponse.class);
+
+ response.invite.postDeserialize();
+
+ return response.invite;
+ }
+
+
+ /**
+ * Updates an existing account user.
+ *
+ * @param userId the ID of the user to update
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return the updated {@link User} object
+ */
+ public User updateUser(String userId) throws MailerSendException {
+
+ if (userId == null || userId.isBlank()) {
+
+ throw new MailerSendException("User ID cannot be null or empty");
+ }
+
+ if (builderBody.role == null || builderBody.role.isBlank()) {
+
+ throw new MailerSendException("User role cannot be null or empty");
+ }
+
+ if ("Custom User".equals(builderBody.role) && builderBody.permissions.isEmpty()) {
+
+ throw new MailerSendException("Permissions are required for Custom User role");
+ }
+
+ String endpoint = "/users/".concat(userId);
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ Gson gson = new GsonBuilder()
+ .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false))
+ .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true))
+ .create();
+
+ String json = gson.toJson(builderBody);
+
+ builderBody.reset();
+
+ UserResponse response = api.putRequest(endpoint, json, UserResponse.class);
+
+ response.user.postDeserialize();
+
+ return response.user;
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/users/UserDomain.java b/src/main/java/com/mailersend/sdk/users/UserDomain.java
new file mode 100644
index 0000000..50146b4
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/users/UserDomain.java
@@ -0,0 +1,71 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.users;
+
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.util.Date;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Represents a domain object within a user or invite response.
+ */
+public class UserDomain {
+
+ @SerializedName("id")
+ public String id;
+
+ @SerializedName("name")
+ public String name;
+
+ public Date createdAt;
+
+ @SerializedName("created_at")
+ private String createdAtStr;
+
+ public Date updatedAt;
+
+ @SerializedName("updated_at")
+ private String updatedAtStr;
+
+
+ /**
+ * Is called to perform any actions after the deserialization of the response.
+ * Do not call directly.
+ */
+ protected void postDeserialize() {
+
+ parseDates();
+ }
+
+
+ /**
+ * Parses the string dates from the response into java.util.Date objects.
+ */
+ private void parseDates() {
+
+ TemporalAccessor ta;
+ Instant instant;
+
+ if (createdAtStr != null && !createdAtStr.isBlank()) {
+
+ ta = DateTimeFormatter.ISO_INSTANT.parse(createdAtStr);
+ instant = Instant.from(ta);
+ createdAt = Date.from(instant);
+ }
+
+ if (updatedAtStr != null && !updatedAtStr.isBlank()) {
+
+ ta = DateTimeFormatter.ISO_INSTANT.parse(updatedAtStr);
+ instant = Instant.from(ta);
+ updatedAt = Date.from(instant);
+ }
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/users/UserRequestBody.java b/src/main/java/com/mailersend/sdk/users/UserRequestBody.java
new file mode 100644
index 0000000..dd948b3
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/users/UserRequestBody.java
@@ -0,0 +1,50 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.users;
+
+import java.util.ArrayList;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Serializable body for create/update user (invite) requests.
+ */
+class UserRequestBody {
+
+ @SerializedName("email")
+ public String email = null;
+
+ @SerializedName("role")
+ public String role = null;
+
+ @SerializedName("permissions")
+ public ArrayList permissions = new ArrayList();
+
+ @SerializedName("templates")
+ public ArrayList templates = new ArrayList();
+
+ @SerializedName("domains")
+ public ArrayList domains = new ArrayList();
+
+ @SerializedName("requires_periodic_password_change")
+ public Boolean requiresPeriodicPasswordChange = null;
+
+
+ /**
+ * Resets all fields so that the object can be reused.
+ */
+ public void reset() {
+
+ email = null;
+ role = null;
+ permissions.clear();
+ templates.clear();
+ domains.clear();
+ requiresPeriodicPasswordChange = null;
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/users/UserResponse.java b/src/main/java/com/mailersend/sdk/users/UserResponse.java
new file mode 100644
index 0000000..f640f69
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/users/UserResponse.java
@@ -0,0 +1,20 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.users;
+
+import com.google.gson.annotations.SerializedName;
+import com.mailersend.sdk.MailerSendResponse;
+
+/**
+ * Wraps a single user response from the API.
+ */
+public class UserResponse extends MailerSendResponse {
+
+ @SerializedName("data")
+ public User user;
+}
diff --git a/src/main/java/com/mailersend/sdk/users/UserTemplate.java b/src/main/java/com/mailersend/sdk/users/UserTemplate.java
new file mode 100644
index 0000000..52e77f2
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/users/UserTemplate.java
@@ -0,0 +1,62 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.users;
+
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.util.Date;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Represents a template object within a user response.
+ */
+public class UserTemplate {
+
+ @SerializedName("id")
+ public String id;
+
+ @SerializedName("name")
+ public String name;
+
+ @SerializedName("type")
+ public String type;
+
+ public Date createdAt;
+
+ @SerializedName("created_at")
+ private String createdAtStr;
+
+
+ /**
+ * Is called to perform any actions after the deserialization of the response.
+ * Do not call directly.
+ */
+ protected void postDeserialize() {
+
+ parseDates();
+ }
+
+
+ /**
+ * Parses the string dates from the response into java.util.Date objects.
+ */
+ private void parseDates() {
+
+ TemporalAccessor ta;
+ Instant instant;
+
+ if (createdAtStr != null && !createdAtStr.isBlank()) {
+
+ ta = DateTimeFormatter.ISO_INSTANT.parse(createdAtStr);
+ instant = Instant.from(ta);
+ createdAt = Date.from(instant);
+ }
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/users/Users.java b/src/main/java/com/mailersend/sdk/users/Users.java
new file mode 100644
index 0000000..165dbd4
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/users/Users.java
@@ -0,0 +1,263 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.users;
+
+import java.util.ArrayList;
+import java.util.stream.IntStream;
+
+import com.mailersend.sdk.MailerSend;
+import com.mailersend.sdk.MailerSendApi;
+import com.mailersend.sdk.MailerSendResponse;
+import com.mailersend.sdk.exceptions.MailerSendException;
+
+/**
+ * Provides access to the Users and Invites endpoints of the MailerSend API.
+ *
+ * Do not instantiate directly — access via {@code MailerSend.users()}.
+ */
+public class Users {
+
+ private final MailerSend apiObjectReference;
+
+ private final UserBuilder userBuilder;
+
+ private int pageFilter = 1;
+ private int limitFilter = 25;
+
+
+ /**
+ * Do not initialize directly. This should only be accessed from MailerSend.users().
+ *
+ * @param apiObjectRef a {@link com.mailersend.sdk.MailerSend} object.
+ */
+ public Users(MailerSend apiObjectRef) {
+
+ apiObjectReference = apiObjectRef;
+ userBuilder = new UserBuilder(apiObjectRef);
+ }
+
+
+ /**
+ * Set the page of the request.
+ *
+ * @param page the page number (min: 1)
+ * @return this Users object (for chaining)
+ */
+ public Users page(int page) {
+
+ pageFilter = page;
+
+ return this;
+ }
+
+
+ /**
+ * Set the results limit (10 - 100).
+ *
+ * @param limit the number of results per page
+ * @return this Users object (for chaining)
+ */
+ public Users limit(int limit) {
+
+ limitFilter = limit;
+
+ return this;
+ }
+
+
+ /**
+ * Returns the builder used to create or update users.
+ *
+ * @return a {@link UserBuilder} object
+ */
+ public UserBuilder builder() {
+
+ return userBuilder;
+ }
+
+
+ // -------------------------------------------------------------------------
+ // Users
+ // -------------------------------------------------------------------------
+
+ /**
+ * Gets a paginated list of account users.
+ *
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link UsersList} object
+ */
+ public UsersList getUsers() throws MailerSendException {
+
+ String endpoint = "/users".concat(preparePaginationParams());
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ UsersList response = api.getRequest(endpoint, UsersList.class);
+
+ response.postDeserialize();
+
+ return response;
+ }
+
+
+ /**
+ * Gets a single account user by ID.
+ *
+ * @param userId the ID of the user to retrieve
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return a {@link User} object
+ */
+ public User getUser(String userId) throws MailerSendException {
+
+ String endpoint = "/users/".concat(userId);
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ UserResponse response = api.getRequest(endpoint, UserResponse.class);
+
+ response.user.postDeserialize();
+
+ return response.user;
+ }
+
+
+ /**
+ * Deletes a user from the account.
+ *
+ * @param userId the ID of the user to delete
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return {@code true} if the deletion was successful
+ */
+ public boolean deleteUser(String userId) throws MailerSendException {
+
+ String endpoint = "/users/".concat(userId);
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ MailerSendResponse response = api.deleteRequest(endpoint, MailerSendResponse.class);
+
+ return IntStream.of(new int[]{200, 204, 202}).anyMatch(x -> x == response.responseStatusCode);
+ }
+
+
+ // -------------------------------------------------------------------------
+ // Invites
+ // -------------------------------------------------------------------------
+
+ /**
+ * Gets a paginated list of pending invites.
+ *
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return an {@link InvitesList} object
+ */
+ public InvitesList getInvites() throws MailerSendException {
+
+ String endpoint = "/invites".concat(preparePaginationParams());
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ InvitesList response = api.getRequest(endpoint, InvitesList.class);
+
+ response.postDeserialize();
+
+ return response;
+ }
+
+
+ /**
+ * Gets a single invite by ID.
+ *
+ * @param inviteId the ID of the invite to retrieve
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return an {@link Invite} object
+ */
+ public Invite getInvite(String inviteId) throws MailerSendException {
+
+ String endpoint = "/invites/".concat(inviteId);
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ InviteResponse response = api.getRequest(endpoint, InviteResponse.class);
+
+ response.invite.postDeserialize();
+
+ return response.invite;
+ }
+
+
+ /**
+ * Resends a pending invite.
+ *
+ * @param inviteId the ID of the invite to resend
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return the updated {@link Invite} object
+ */
+ public Invite resendInvite(String inviteId) throws MailerSendException {
+
+ String endpoint = "/invites/".concat(inviteId).concat("/resend");
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ InviteResponse response = api.postRequest(endpoint, "{}", InviteResponse.class);
+
+ response.invite.postDeserialize();
+
+ return response.invite;
+ }
+
+
+ /**
+ * Cancels (deletes) a pending invite.
+ *
+ * @param inviteId the ID of the invite to cancel
+ * @throws com.mailersend.sdk.exceptions.MailerSendException
+ * @return {@code true} if the cancellation was successful
+ */
+ public boolean deleteInvite(String inviteId) throws MailerSendException {
+
+ String endpoint = "/invites/".concat(inviteId);
+
+ MailerSendApi api = new MailerSendApi();
+ api.setToken(apiObjectReference.getToken());
+
+ MailerSendResponse response = api.deleteRequest(endpoint, MailerSendResponse.class);
+
+ return IntStream.of(new int[]{200, 204, 202}).anyMatch(x -> x == response.responseStatusCode);
+ }
+
+
+ // -------------------------------------------------------------------------
+ // Helpers
+ // -------------------------------------------------------------------------
+
+ /**
+ * Builds the query string for paginated list requests.
+ */
+ private String preparePaginationParams() {
+
+ ArrayList params = new ArrayList();
+
+ params.add("page=".concat(String.valueOf(pageFilter)));
+ params.add("limit=".concat(String.valueOf(limitFilter)));
+
+ StringBuilder requestParams = new StringBuilder();
+
+ for (int i = 0; i < params.size(); i++) {
+
+ requestParams.append(i == 0 ? "?" : "&").append(params.get(i));
+ }
+
+ return requestParams.toString();
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/users/UsersList.java b/src/main/java/com/mailersend/sdk/users/UsersList.java
new file mode 100644
index 0000000..ba57746
--- /dev/null
+++ b/src/main/java/com/mailersend/sdk/users/UsersList.java
@@ -0,0 +1,33 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.users;
+
+import com.google.gson.annotations.SerializedName;
+import com.mailersend.sdk.util.PaginatedResponse;
+
+/**
+ * Wraps a paginated list of users from the API.
+ */
+public class UsersList extends PaginatedResponse {
+
+ @SerializedName("data")
+ public User[] users;
+
+
+ /**
+ * postDeserialize.
+ */
+ protected void postDeserialize() {
+
+ if (users != null) {
+ for (User user : users) {
+ user.postDeserialize();
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/mailersend/sdk/util/EventTypes.java b/src/main/java/com/mailersend/sdk/util/EventTypes.java
index 1c924c3..6f5d02e 100644
--- a/src/main/java/com/mailersend/sdk/util/EventTypes.java
+++ b/src/main/java/com/mailersend/sdk/util/EventTypes.java
@@ -40,4 +40,19 @@ public class EventTypes {
/** Constant SPAM_COMPLAINTS="spam_complaints" */
public static final String SPAM_COMPLAINTS = "spam_complaints";
+
+ /** Constant DEFERRED="deferred" */
+ public static final String DEFERRED = "deferred";
+
+ /** Constant OPENED_UNIQUE="opened_unique" */
+ public static final String OPENED_UNIQUE = "opened_unique";
+
+ /** Constant CLICKED_UNIQUE="clicked_unique" */
+ public static final String CLICKED_UNIQUE = "clicked_unique";
+
+ /** Constant SURVEY_OPENED="survey_opened" */
+ public static final String SURVEY_OPENED = "survey_opened";
+
+ /** Constant SURVEY_SUBMITTED="survey_submitted" */
+ public static final String SURVEY_SUBMITTED = "survey_submitted";
}
diff --git a/src/main/java/com/mailersend/sdk/webhooks/Webhooks.java b/src/main/java/com/mailersend/sdk/webhooks/Webhooks.java
index 9b26ac2..bc78851 100644
--- a/src/main/java/com/mailersend/sdk/webhooks/Webhooks.java
+++ b/src/main/java/com/mailersend/sdk/webhooks/Webhooks.java
@@ -48,25 +48,37 @@ public Webhooks(MailerSend apiObjectRef) {
*
* @param page a int.
* @return a {@link com.mailersend.sdk.webhooks.Webhooks} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException if page is less than 1.
*/
- public Webhooks page(int page) {
-
+ public Webhooks page(int page) throws MailerSendException {
+
+ if (page < 1) {
+
+ throw new MailerSendException("Page must be at least 1");
+ }
+
pageFilter = page;
-
+
return this;
}
-
-
+
+
/**
* Set the results limit (10 - 100)
*
* @param limit a int.
* @return a {@link com.mailersend.sdk.webhooks.Webhooks} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException if limit is not between 10 and 100.
*/
- public Webhooks limit(int limit) {
-
+ public Webhooks limit(int limit) throws MailerSendException {
+
+ if (limit < 10 || limit > 100) {
+
+ throw new MailerSendException("Limit must be between 10 and 100");
+ }
+
limitFilter = limit;
-
+
return this;
}
@@ -90,7 +102,12 @@ public WebhooksBuilder builder() {
* @return a {@link com.mailersend.sdk.webhooks.WebhooksList} object.
*/
public WebhooksList getWebhooks(String domainId) throws MailerSendException {
-
+
+ if (domainId == null || domainId.isBlank()) {
+
+ throw new MailerSendException("Domain ID cannot be empty");
+ }
+
String endpoint = "/webhooks".concat(prepareParamsUrl(domainId));
MailerSendApi api = new MailerSendApi();
diff --git a/src/main/java/com/mailersend/sdk/webhooks/WebhooksBuilder.java b/src/main/java/com/mailersend/sdk/webhooks/WebhooksBuilder.java
index 15ef6dd..a0d627c 100644
--- a/src/main/java/com/mailersend/sdk/webhooks/WebhooksBuilder.java
+++ b/src/main/java/com/mailersend/sdk/webhooks/WebhooksBuilder.java
@@ -89,9 +89,57 @@ public WebhooksBuilder addEvent(String event) {
* @return a {@link com.mailersend.sdk.webhooks.WebhooksBuilder} object.
*/
public WebhooksBuilder clearEvents() {
-
+
builderBody.events.clear();
-
+
+ return this;
+ }
+
+
+ /**
+ * Set whether the webhook is editable
+ *
+ * @param editable a boolean.
+ * @return a {@link com.mailersend.sdk.webhooks.WebhooksBuilder} object.
+ */
+ public WebhooksBuilder editable(boolean editable) {
+
+ builderBody.editable = editable;
+
+ return this;
+ }
+
+
+ /**
+ * Set whether the webhook is enabled
+ *
+ * @param enabled a boolean.
+ * @return a {@link com.mailersend.sdk.webhooks.WebhooksBuilder} object.
+ */
+ public WebhooksBuilder enabled(boolean enabled) {
+
+ builderBody.enabled = enabled;
+
+ return this;
+ }
+
+
+ /**
+ * Set the webhook version (1 or 2)
+ *
+ * @param version an int (valid values: 1 or 2).
+ * @return a {@link com.mailersend.sdk.webhooks.WebhooksBuilder} object.
+ * @throws com.mailersend.sdk.exceptions.MailerSendException if the version is not 1 or 2.
+ */
+ public WebhooksBuilder version(int version) throws MailerSendException {
+
+ if (version != 1 && version != 2) {
+
+ throw new MailerSendException("Webhook version must be 1 or 2");
+ }
+
+ builderBody.version = version;
+
return this;
}
@@ -123,13 +171,18 @@ public Webhook createWebhook(String domainId) throws MailerSendException {
}
+ if (builderBody.events.isEmpty()) {
+
+ throw new MailerSendException("At least one webhook event is required");
+ }
+
for (String event : builderBody.events) {
if (!Arrays.asList(WebhookEvents.events).contains(event)) {
-
+
throw new MailerSendException("Webhook event is not valid");
}
}
-
+
String endpoint = "/webhooks";
MailerSendApi api = new MailerSendApi();
diff --git a/src/main/java/com/mailersend/sdk/webhooks/WebhooksBuilderBody.java b/src/main/java/com/mailersend/sdk/webhooks/WebhooksBuilderBody.java
index a0e4f28..9b367bc 100644
--- a/src/main/java/com/mailersend/sdk/webhooks/WebhooksBuilderBody.java
+++ b/src/main/java/com/mailersend/sdk/webhooks/WebhooksBuilderBody.java
@@ -24,24 +24,34 @@ class WebhooksBuilderBody {
@SerializedName("enabled")
public Boolean enabled = null;
-
+
@SerializedName("domain_id")
public String domainId;
-
-
+
+ @SerializedName("editable")
+ public Boolean editable = null;
+
+ @SerializedName("version")
+ public Integer version = null;
+
+
/**
* Resets the values so that the object can be reused
*/
public void reset() {
-
+
url = null;
-
+
name = null;
-
+
events = new ArrayList();
-
+
enabled = null;
-
+
domainId = null;
+
+ editable = null;
+
+ version = null;
}
}
diff --git a/src/main/java/com/mailersend/sms/webhooks/SmsWebhooksBuilder.java b/src/main/java/com/mailersend/sms/webhooks/SmsWebhooksBuilder.java
index 257bf1c..9905c36 100644
--- a/src/main/java/com/mailersend/sms/webhooks/SmsWebhooksBuilder.java
+++ b/src/main/java/com/mailersend/sms/webhooks/SmsWebhooksBuilder.java
@@ -81,6 +81,20 @@ public SmsWebhooksBuilder addEvent(String event) {
}
+ /**
+ * Set whether the webhook is enabled
+ *
+ * @param enabled a boolean.
+ * @return a {@link com.mailersend.sms.webhooks.SmsWebhooksBuilder} object.
+ */
+ public SmsWebhooksBuilder enabled(boolean enabled) {
+
+ builderBody.enabled = enabled;
+
+ return this;
+ }
+
+
/**
* Clears the events of the webhook request
*
diff --git a/src/main/java/com/mailsend/sdk/emailverification/EmailVerification.java b/src/main/java/com/mailsend/sdk/emailverification/EmailVerification.java
deleted file mode 100644
index 442882a..0000000
--- a/src/main/java/com/mailsend/sdk/emailverification/EmailVerification.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*************************************************
- * MailerSend Java SDK
- * https://github.com/mailersend/mailersend-java
- *
- * @author MailerSend
- * https://mailersend.com
- **************************************************/
-package com.mailsend.sdk.emailverification;
-
-import java.util.ArrayList;
-
-import com.mailersend.sdk.MailerSend;
-import com.mailersend.sdk.MailerSendApi;
-import com.mailersend.sdk.exceptions.MailerSendException;
-
-/**
- * EmailVerification class.
- *
- * @author mailersend
- * @version $Id: $Id
- */
-public class EmailVerification {
- private MailerSend apiObjectReference;
-
- private int pageFilter = 1;
- private int limitFilter = 25;
-
- private EmailVerificationBuilder builder;
-
- /**
- * Constructor for EmailVerification.
- *
- * @param ref a {@link com.mailersend.sdk.MailerSend} object.
- */
- public EmailVerification(MailerSend ref) {
- apiObjectReference = ref;
- builder = new EmailVerificationBuilder(ref);
- }
-
- /**
- * page.
- *
- * @param page a int.
- * @return a {@link com.mailsend.sdk.emailverification.EmailVerification} object.
- */
- public EmailVerification page(int page) {
- pageFilter = page;
- return this;
- }
-
- /**
- * limit.
- *
- * @param limit a int.
- * @return a {@link com.mailsend.sdk.emailverification.EmailVerification} object.
- */
- public EmailVerification limit(int limit) {
- limitFilter = limit;
- return this;
- }
-
- /**
- * builder.
- *
- * @return a {@link com.mailsend.sdk.emailverification.EmailVerificationBuilder} object.
- */
- public EmailVerificationBuilder builder() {
- return builder;
- }
-
- /**
- * newBuilder.
- *
- * @return a {@link com.mailsend.sdk.emailverification.EmailVerificationBuilder} object.
- */
- public EmailVerificationBuilder newBuilder() {
- return new EmailVerificationBuilder(apiObjectReference);
- }
-
- /**
- * getLists.
- *
- * @return a {@link com.mailsend.sdk.emailverification.EmailVerificationLists} object.
- * @throws com.mailersend.sdk.exceptions.MailerSendException if any.
- */
- public EmailVerificationLists getLists() throws MailerSendException {
- String endpoint = "/email-verification".concat(prepareParamsUrl());
-
- MailerSendApi api = new MailerSendApi();
- api.setToken(apiObjectReference.getToken());
-
- EmailVerificationLists lists = api.getRequest(endpoint, EmailVerificationLists.class);
-
- for (EmailVerificationList l : lists.lists) {
- l.postDeserialize();
- }
-
- return lists;
- }
-
- /**
- * getList.
- *
- * @param emailVerificationId a {@link java.lang.String} object.
- * @return a {@link com.mailsend.sdk.emailverification.EmailVerificationList} object.
- * @throws com.mailersend.sdk.exceptions.MailerSendException if any.
- */
- public EmailVerificationList getList(String emailVerificationId) throws MailerSendException {
- String endpoint = "/email-verification/".concat(emailVerificationId);
-
- MailerSendApi api = new MailerSendApi();
- api.setToken(apiObjectReference.getToken());
-
- SingleEmailVerificationListResponse response = api.getRequest(endpoint, SingleEmailVerificationListResponse.class);
-
- response.list.postDeserialize();
-
- return response.list;
- }
-
- /**
- * verifyList.
- *
- * @param listId a {@link java.lang.String} object.
- * @return a {@link com.mailsend.sdk.emailverification.EmailVerificationList} object.
- * @throws com.mailersend.sdk.exceptions.MailerSendException if any.
- */
- public EmailVerificationList verifyList(String listId) throws MailerSendException {
- String endpoint = "/email-verification/".concat(listId).concat("/verify");
-
- MailerSendApi api = new MailerSendApi();
- api.setToken(apiObjectReference.getToken());
-
- SingleEmailVerificationListResponse response = api.getRequest(endpoint, SingleEmailVerificationListResponse.class);
-
- response.list.postDeserialize();
-
- return response.list;
- }
-
- /**
- * verificationResults.
- *
- * @param listId a {@link java.lang.String} object.
- * @return a {@link com.mailsend.sdk.emailverification.ListVerificationResults} object.
- * @throws com.mailersend.sdk.exceptions.MailerSendException if any.
- */
- public ListVerificationResults verificationResults(String listId) throws MailerSendException {
- String endpoint = "/email-verification/".concat(listId).concat("/results");
-
- MailerSendApi api = new MailerSendApi();
- api.setToken(apiObjectReference.getToken());
-
- ListVerificationResults response = api.getRequest(endpoint, ListVerificationResults.class);
-
- return response;
- }
-
- /**
- * Prepares the query part of the request url
- * @return
- */
- private String prepareParamsUrl() {
-
- // prepare the request parameters
- ArrayList params = new ArrayList();
-
- params.add("page=".concat(String.valueOf(pageFilter)));
-
- params.add("limit=".concat(String.valueOf(limitFilter)));
-
- String requestParams = "";
- for (int i = 0; i < params.size(); i++) {
-
- String attrSep = "&";
-
- if (i == 0) {
-
- attrSep = "?";
- }
-
- requestParams = requestParams.concat(attrSep).concat(params.get(i));
- }
-
- return requestParams;
- }
-}
diff --git a/src/test/java/com/mailersend/sdk/tests/ActivitiesTest.java b/src/test/java/com/mailersend/sdk/tests/ActivitiesTest.java
index 863c282..da6c44c 100644
--- a/src/test/java/com/mailersend/sdk/tests/ActivitiesTest.java
+++ b/src/test/java/com/mailersend/sdk/tests/ActivitiesTest.java
@@ -9,6 +9,7 @@
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
+import java.util.Calendar;
import java.util.Date;
import org.junit.jupiter.api.AfterEach;
@@ -43,7 +44,7 @@ public void afterEach() throws IOException
* Tests that the date of the dateFrom filter can't be after the dateTo filter
*/
@Test
- public void TestDateFromAfterDateTo() {
+ public void testDateFromAfterDateTo() {
TemporalAccessor ta;
Instant instant;
@@ -78,20 +79,25 @@ public void TestDateFromAfterDateTo() {
* Make sure your account has some activities
*/
@Test
- public void TestGetActivities() {
-
+ public void testGetActivities() {
+
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
- ActivitiesList activities = ms.activities().getActivities(TestHelper.domainId);
-
+
+ Calendar cal = Calendar.getInstance();
+ Date dateTo = cal.getTime();
+ cal.add(Calendar.DAY_OF_MONTH, -30);
+ Date dateFrom = cal.getTime();
+
+ ActivitiesList activities = ms.activities().getActivities(TestHelper.domainId, 1, 25, dateFrom, dateTo, null);
+
assertTrue(activities.activities.length > 0);
-
+
} catch (MailerSendException e) {
-
+
fail();
}
}
@@ -102,23 +108,28 @@ public void TestGetActivities() {
* Make sure your account has more than 10 activities
*/
@Test
- public void TestActivitiesPagination() {
-
+ public void testActivitiesPagination() {
+
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
- ActivitiesList activities = ms.activities().getActivities(TestHelper.domainId, 1, 10, null, null, null);
-
+
+ Calendar cal = Calendar.getInstance();
+ Date dateTo = cal.getTime();
+ cal.add(Calendar.DAY_OF_MONTH, -30);
+ Date dateFrom = cal.getTime();
+
+ ActivitiesList activities = ms.activities().getActivities(TestHelper.domainId, 1, 10, dateFrom, dateTo, null);
+
assertTrue(activities.activities.length > 0);
-
- ActivitiesList secondPage = ms.activities().getActivities(TestHelper.domainId, 2, 10, null, null, null);
-
+
+ ActivitiesList secondPage = ms.activities().getActivities(TestHelper.domainId, 2, 10, dateFrom, dateTo, null);
+
assertTrue(secondPage.activities.length > 0);
-
- assertNotEquals(secondPage.activities[0].id, activities.activities[0].id);
-
+
+ assertNotEquals(secondPage.activities[0].id, activities.activities[0].id);
+
} catch (MailerSendException e) {
fail();
@@ -131,22 +142,27 @@ public void TestActivitiesPagination() {
* Make sure you have some activities with status opened
*/
@Test
- public void TestActivitiesFilterByEvent() {
-
+ public void testActivitiesFilterByEvent() {
+
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
- ActivitiesList activities = ms.activities().getActivities(TestHelper.domainId, 1, 100, null, null, new String[] { EventTypes.OPENED });
-
+
+ Calendar cal = Calendar.getInstance();
+ Date dateTo = cal.getTime();
+ cal.add(Calendar.DAY_OF_MONTH, -30);
+ Date dateFrom = cal.getTime();
+
+ ActivitiesList activities = ms.activities().getActivities(TestHelper.domainId, 1, 100, dateFrom, dateTo, new String[] { EventTypes.OPENED });
+
assertTrue(activities.activities.length > 0);
-
+
for (Activity activity : activities.activities) {
-
+
assertTrue(activity.type.equals(EventTypes.OPENED));
}
-
+
} catch (MailerSendException e) {
fail();
@@ -158,29 +174,34 @@ public void TestActivitiesFilterByEvent() {
* Tests the contents of a single activity
*/
@Test
- public void TestSingleActivity() {
-
+ public void testSingleActivity() {
+
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
- ActivitiesList activities = ms.activities().getActivities(TestHelper.domainId, 1, 10, null, null, null);
-
+
+ Calendar cal = Calendar.getInstance();
+ Date dateTo = cal.getTime();
+ cal.add(Calendar.DAY_OF_MONTH, -30);
+ Date dateFrom = cal.getTime();
+
+ ActivitiesList activities = ms.activities().getActivities(TestHelper.domainId, 1, 10, dateFrom, dateTo, null);
+
assertTrue(activities.activities.length > 0);
-
+
Activity activity = activities.activities[0];
-
+
assertTrue(activity.id != null && !activity.id.isBlank());
assertTrue(activity.type != null && !activity.type.isBlank());
-
+
assertTrue(activity.email != null);
assertTrue(activity.email.from != null && !activity.email.from.isBlank());
assertTrue(activity.email.subject != null && !activity.email.subject.isBlank());
assertTrue(activity.email.id != null && !activity.email.id.isBlank());
assertTrue(activity.email.status != null && !activity.email.status.isBlank());
assertTrue(activity.email.createdAt != null);
-
+
} catch (MailerSendException e) {
fail();
@@ -192,29 +213,34 @@ public void TestSingleActivity() {
* Tests the conversion of an activity to an email ready to be sent
*/
@Test
- public void TestActivityEmailConversion() {
-
+ public void testActivityEmailConversion() {
+
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
- ActivitiesList activities = ms.activities().getActivities(TestHelper.domainId, 1, 10, null, null, null);
-
+
+ Calendar cal = Calendar.getInstance();
+ Date dateTo = cal.getTime();
+ cal.add(Calendar.DAY_OF_MONTH, -30);
+ Date dateFrom = cal.getTime();
+
+ ActivitiesList activities = ms.activities().getActivities(TestHelper.domainId, 1, 10, dateFrom, dateTo, null);
+
assertTrue(activities.activities.length > 0);
-
+
Activity activity = activities.activities[0];
-
+
Email email = activity.email.toEmail();
-
+
assertEquals(email.subject, activity.email.subject);
assertEquals(email.from.email, activity.email.from);
assertEquals(email.text, activity.email.text);
assertEquals(email.html, activity.email.html);
-
+
} catch (MailerSendException e) {
fail();
- }
+ }
}
}
diff --git a/src/test/java/com/mailersend/sdk/tests/AnalyticsTest.java b/src/test/java/com/mailersend/sdk/tests/AnalyticsTest.java
index aac7445..56f7956 100644
--- a/src/test/java/com/mailersend/sdk/tests/AnalyticsTest.java
+++ b/src/test/java/com/mailersend/sdk/tests/AnalyticsTest.java
@@ -42,7 +42,7 @@ public void afterEach() throws IOException
* Gets analytics by date using date filters
*/
@Test
- public void TestAnalyticsByDate() {
+ public void testAnalyticsByDate() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -82,7 +82,7 @@ public void TestAnalyticsByDate() {
* Tests analytics by date for a domain
*/
@Test
- public void TestAnalyticsByDateDomain() {
+ public void testAnalyticsByDateDomain() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -123,7 +123,7 @@ public void TestAnalyticsByDateDomain() {
* Tests opens by country
*/
@Test
- public void TestAnalyticsOpensByCountry() {
+ public void testAnalyticsOpensByCountry() {
MailerSend ms = new MailerSend();
@@ -162,7 +162,7 @@ public void TestAnalyticsOpensByCountry() {
* Tests opens by user agent
*/
@Test
- public void TestAnalyticsOpensByUa() {
+ public void testAnalyticsOpensByUa() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -198,7 +198,7 @@ public void TestAnalyticsOpensByUa() {
* Tests opens by reading environment
*/
@Test
- public void TestAnalyticsOpensByUaType() {
+ public void testAnalyticsOpensByUaType() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -215,7 +215,7 @@ public void TestAnalyticsOpensByUaType() {
AnalyticsList list = ms.analytics()
.dateFrom(dateFrom)
.dateTo(dateTo)
- .getOpensByUserAgenType();
+ .getOpensByUserAgentType();
System.out.println("\n\nOpens by user agent type:");
diff --git a/src/test/java/com/mailersend/sdk/tests/BlocklistMonitoringTest.java b/src/test/java/com/mailersend/sdk/tests/BlocklistMonitoringTest.java
new file mode 100644
index 0000000..1bae7e6
--- /dev/null
+++ b/src/test/java/com/mailersend/sdk/tests/BlocklistMonitoringTest.java
@@ -0,0 +1,157 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.tests;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+
+import com.mailersend.sdk.MailerSend;
+import com.mailersend.sdk.blocklistmonitoring.BlocklistMonitor;
+import com.mailersend.sdk.blocklistmonitoring.BlocklistMonitorsList;
+import com.mailersend.sdk.exceptions.MailerSendException;
+import com.mailersend.sdk.vcr.VcrRecorder;
+
+public class BlocklistMonitoringTest {
+
+ @BeforeEach
+ public void setupEach(TestInfo info) throws IOException {
+ VcrRecorder.useRecording("BlocklistMonitoringTest_" + info.getDisplayName());
+ }
+
+ @AfterEach
+ public void afterEach() throws IOException {
+ VcrRecorder.stopRecording();
+ }
+
+ /**
+ * Tests listing blocklist monitors
+ */
+ @Test
+ public void getMonitorsTest() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ BlocklistMonitorsList list = ms.blocklistMonitoring().getMonitors();
+
+ assertNotNull(list);
+ for (BlocklistMonitor monitor : list.monitors) {
+ System.out.println(monitor.id);
+ System.out.println(monitor.address);
+ }
+
+ } catch (MailerSendException e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ /**
+ * Tests retrieving a single blocklist monitor
+ */
+ @Test
+ public void getMonitorTest() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ BlocklistMonitor monitor = ms.blocklistMonitoring().getMonitor(TestHelper.blocklistMonitorId);
+
+ assertNotNull(monitor);
+ System.out.println(monitor.id);
+ System.out.println(monitor.address);
+
+ } catch (MailerSendException e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ /**
+ * Tests creating a blocklist monitor
+ */
+ @Test
+ public void createMonitorTest() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ BlocklistMonitor monitor = ms.blocklistMonitoring().createMonitorBuilder()
+ .createMonitor(TestHelper.blocklistMonitorAddress);
+
+ assertNotNull(monitor);
+ System.out.println(monitor.id);
+ System.out.println(monitor.address);
+
+ } catch (MailerSendException e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ /**
+ * Tests updating a blocklist monitor
+ */
+ @Test
+ public void updateMonitorTest() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ BlocklistMonitor monitor = ms.blocklistMonitoring().updateMonitorBuilder()
+ .name("updated-monitor")
+ .updateMonitor(TestHelper.blocklistMonitorId);
+
+ assertNotNull(monitor);
+ System.out.println(monitor.id);
+ System.out.println(monitor.name);
+
+ } catch (MailerSendException e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ /**
+ * Tests deleting a blocklist monitor
+ */
+ @Test
+ public void deleteMonitorTest() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ boolean deleted = ms.blocklistMonitoring().deleteMonitor(TestHelper.blocklistMonitorId);
+
+ assertTrue(deleted);
+ System.out.println("Monitor deleted: " + deleted);
+
+ } catch (MailerSendException e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+}
diff --git a/src/test/java/com/mailersend/sdk/tests/DmarcMonitoringTest.java b/src/test/java/com/mailersend/sdk/tests/DmarcMonitoringTest.java
index 999279e..3ecb984 100644
--- a/src/test/java/com/mailersend/sdk/tests/DmarcMonitoringTest.java
+++ b/src/test/java/com/mailersend/sdk/tests/DmarcMonitoringTest.java
@@ -7,6 +7,8 @@
**************************************************/
package com.mailersend.sdk.tests;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
@@ -44,7 +46,7 @@ public void afterEach() throws IOException {
* Tests listing DMARC monitors
*/
@Test
- public void ListMonitorsTest() {
+ public void listMonitorsTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -69,7 +71,7 @@ public void ListMonitorsTest() {
* Tests creating a DMARC monitor
*/
@Test
- public void CreateMonitorTest() {
+ public void createMonitorTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -92,7 +94,7 @@ public void CreateMonitorTest() {
* Tests updating a DMARC monitor
*/
@Test
- public void UpdateMonitorTest() {
+ public void updateMonitorTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -116,7 +118,7 @@ public void UpdateMonitorTest() {
* Tests deleting a DMARC monitor
*/
@Test
- public void DeleteMonitorTest() {
+ public void deleteMonitorTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -137,7 +139,7 @@ public void DeleteMonitorTest() {
* Tests retrieving aggregated DMARC reports
*/
@Test
- public void GetAggregatedReportTest() {
+ public void getAggregatedReportTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -162,7 +164,7 @@ public void GetAggregatedReportTest() {
* Tests retrieving IP-specific DMARC reports
*/
@Test
- public void GetIpReportTest() {
+ public void getIpReportTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -187,14 +189,17 @@ public void GetIpReportTest() {
* Tests retrieving DMARC report sources
*/
@Test
- public void GetReportSourcesTest() {
+ public void getReportSourcesTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
try {
- DmarcReportSourcesList list = ms.dmarcMonitoring().getReportSources(TestHelper.dmarcMonitorId);
+ DmarcReportSourcesList list = ms.dmarcMonitoring()
+ .dateFrom("2023-01-01")
+ .dateTo("2023-12-31")
+ .getReportSources(TestHelper.dmarcMonitorId);
for (DmarcReportSource source : list.sources) {
System.out.println(source.reportSource);
@@ -211,7 +216,7 @@ public void GetReportSourcesTest() {
* Tests marking an IP as favorite
*/
@Test
- public void MarkIpAsFavoriteTest() {
+ public void markIpAsFavoriteTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -232,7 +237,7 @@ public void MarkIpAsFavoriteTest() {
* Tests removing an IP from favorites
*/
@Test
- public void RemoveIpFromFavoritesTest() {
+ public void removeIpFromFavoritesTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -248,4 +253,68 @@ public void RemoveIpFromFavoritesTest() {
fail();
}
}
+
+ /**
+ * Tests that getReportSources() throws when dateFrom is not set
+ */
+ @Test
+ public void getReportSourcesMissingDateFromTest() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () ->
+ ms.dmarcMonitoring()
+ .dateTo("2023-12-31")
+ .getReportSources(TestHelper.dmarcMonitorId)
+ );
+
+ assertEquals("dateFrom and dateTo are required for getReportSources.", ex.getMessage());
+ }
+
+ /**
+ * Tests that getReportSources() throws when dateTo is not set
+ */
+ @Test
+ public void getReportSourcesMissingDateToTest() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () ->
+ ms.dmarcMonitoring()
+ .dateFrom("2023-01-01")
+ .getReportSources(TestHelper.dmarcMonitorId)
+ );
+
+ assertEquals("dateFrom and dateTo are required for getReportSources.", ex.getMessage());
+ }
+
+ /**
+ * Tests retrieving DMARC report sources with the status filter
+ */
+ @Test
+ public void getReportSourcesWithStatusTest() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ DmarcReportSourcesList list = ms.dmarcMonitoring()
+ .dateFrom("2023-01-01")
+ .dateTo("2023-12-31")
+ .status("accepted")
+ .getReportSources(TestHelper.dmarcMonitorId);
+
+ for (DmarcReportSource source : list.sources) {
+ System.out.println(source.reportSource);
+ System.out.println(source.reports);
+ }
+
+ } catch (MailerSendException e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
}
diff --git a/src/test/java/com/mailersend/sdk/tests/DomainsTest.java b/src/test/java/com/mailersend/sdk/tests/DomainsTest.java
index 1950016..c5fb53f 100644
--- a/src/test/java/com/mailersend/sdk/tests/DomainsTest.java
+++ b/src/test/java/com/mailersend/sdk/tests/DomainsTest.java
@@ -1,5 +1,7 @@
package com.mailersend.sdk.tests;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
@@ -38,7 +40,7 @@ public void afterEach() throws IOException
* Tests domains retrieval
*/
@Test
- public void DomainsListTest() {
+ public void domainsListTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -65,7 +67,7 @@ public void DomainsListTest() {
* Tests the retrieval of a single domain
*/
@Test
- public void SingleDomainTest() {
+ public void singleDomainTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -89,7 +91,7 @@ public void SingleDomainTest() {
* Tests the retrival of recipients per domain
*/
@Test
- public void ReceipientsPerDomainTest() {
+ public void receipientsPerDomainTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -114,7 +116,7 @@ public void ReceipientsPerDomainTest() {
* Tests adding a domain
*/
@Test
- public void AddDomainTest() {
+ public void addDomainTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -138,7 +140,7 @@ public void AddDomainTest() {
* Tests deleting a domain
*/
@Test
- public void DeleteDomainTest() {
+ public void deleteDomainTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -161,7 +163,7 @@ public void DeleteDomainTest() {
* Tests the domain dns records retrieval
*/
@Test
- public void DomainDnsRecordsTest() {
+ public void domainDnsRecordsTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -188,7 +190,7 @@ public void DomainDnsRecordsTest() {
* Tests domain verification
*/
@Test
- public void VerifyDomainTest() {
+ public void verifyDomainTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -211,7 +213,7 @@ public void VerifyDomainTest() {
* Tests updating a domain's settings
*/
@Test
- public void UpdateDomainSettingsTest() {
+ public void updateDomainSettingsTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -234,6 +236,46 @@ public void UpdateDomainSettingsTest() {
}
+ /**
+ * Tests updating a domain's settings with all available fields set
+ */
+ @Test
+ public void testUpdateDomainSettingsAllFields() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ Domain domain = ms.domains().updateDomainSettingsBuilder()
+ .sendPaused(true)
+ .trackClicks(true)
+ .trackOpens(true)
+ .trackUnsubscribe(true)
+ .trackUnsubscribeHtml("Unsubscribe
")
+ .trackUnsubscribeHtmlEnabled(true)
+ .trackUnsubscribePlain("Click here to unsubscribe")
+ .trackUnsubscribePlainEnabled(true)
+ .trackContent(true)
+ .customnTrackingEnabled(true)
+ .customTrackingSubdomain("email")
+ .precedenceBulk(false)
+ .ignoreDuplicatedRecipients(true)
+ .updateDomain(TestHelper.domainId);
+
+ assertNotNull(domain.domainSettings);
+ assertEquals(true, domain.domainSettings.sendPaused);
+ assertEquals(true, domain.domainSettings.trackClicks);
+ assertEquals(true, domain.domainSettings.ignoreDuplicatedRecipients);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
/**
* Simple helper method to print the DomainDnsAttribute properties
* @param attribute
diff --git a/src/test/java/com/mailersend/sdk/tests/EmailConfigurationTest.java b/src/test/java/com/mailersend/sdk/tests/EmailConfigurationTest.java
index 3337463..62ef724 100644
--- a/src/test/java/com/mailersend/sdk/tests/EmailConfigurationTest.java
+++ b/src/test/java/com/mailersend/sdk/tests/EmailConfigurationTest.java
@@ -21,7 +21,7 @@ public class EmailConfigurationTest {
* Tests the from name and email
*/
@Test
- public void TestEmailFromConfiguration() {
+ public void testEmailFromConfiguration() {
Email email = TestHelper.createBasicEmail(true);
@@ -36,7 +36,7 @@ public void TestEmailFromConfiguration() {
* Tests that a single recipient can be added
*/
@Test
- public void TestSingleRecipientConfiguration() {
+ public void testSingleRecipientConfiguration() {
Email email = TestHelper.createBasicEmail(true);
@@ -52,7 +52,7 @@ public void TestSingleRecipientConfiguration() {
* Tests that multiple recipients can be added
*/
@Test
- public void TestMultipleRecipientsConfiguration() {
+ public void testMultipleRecipientsConfiguration() {
String secondRecipientName = "Test Recipient 2";
String secondRecipientEmail = "test@recipient2.com";
@@ -72,7 +72,7 @@ public void TestMultipleRecipientsConfiguration() {
* Tests that the subject, and html and plain bodies are added to the email
*/
@Test
- public void TestEmailContentsConfiguration() {
+ public void testEmailContentsConfiguration() {
Email email = TestHelper.createBasicEmail(true);
@@ -86,7 +86,7 @@ public void TestEmailContentsConfiguration() {
* Tests the email personalization
*/
@Test
- public void TestEmailPersonalization() {
+ public void testEmailPersonalization() {
String personalizationName = "test_personalization";
String personalizationValue = "test_personalization_value";
@@ -130,7 +130,7 @@ public void TestEmailPersonalization() {
* Tests that different recipients can have different personalization
*/
@Test
- public void TestMultipleRecipientsPersonalization() {
+ public void testMultipleRecipientsPersonalization() {
String personalizationName = "test_personalization";
String personalizationValue = "test_personalization_value";
@@ -172,7 +172,7 @@ public void TestMultipleRecipientsPersonalization() {
* Tests that carbon copy recipients can be added to the email
*/
@Test
- public void TestCcRecipients() {
+ public void testCcRecipients() {
Recipient ccRecipient1 = new Recipient("name1", "test1@cc.com");
Recipient ccRecipient2 = new Recipient("name2", "test2@cc.com");
@@ -201,27 +201,160 @@ public void TestCcRecipients() {
* Tests that blind carbon copy recipients can be added to the email
*/
@Test
- public void TestBccRecipients() {
-
+ public void testBccRecipients() {
+
Recipient bccRecipient1 = new Recipient("name1", "test1@bcc.com");
Recipient bccRecipient2 = new Recipient("name2", "test2@bcc.com");
-
+
Email email = TestHelper.createBasicEmail(false);
-
+
// test adding the recipient directly
email.AddBcc(bccRecipient1.name, bccRecipient1.email);
-
+
assertEquals(email.bcc.size(), 1);
-
+
assertTrue(email.bcc.get(0).name.equals(bccRecipient1.name));
assertTrue(email.bcc.get(0).email.equals(bccRecipient1.email));
-
+
// test adding the recipient object
email.AddBcc(bccRecipient2);
-
+
assertEquals(email.bcc.size(), 2);
-
+
assertTrue(email.bcc.get(1).name.equals(bccRecipient2.name));
assertTrue(email.bcc.get(1).email.equals(bccRecipient2.email));
}
+
+
+ /**
+ * Tests that RCPT TO recipients can be added to the email via name/email strings
+ */
+ @Test
+ public void testRcptToRecipientsWithStrings() {
+
+ Email email = TestHelper.createBasicEmail(false);
+
+ email.addRcptTo("rcpt name 1", "rcpt1@client.com");
+
+ assertEquals(1, email.rcptTo.size());
+ assertEquals("rcpt name 1", email.rcptTo.get(0).name);
+ assertEquals("rcpt1@client.com", email.rcptTo.get(0).email);
+
+ email.addRcptTo("rcpt name 2", "rcpt2@client.com");
+
+ assertEquals(2, email.rcptTo.size());
+ assertEquals("rcpt name 2", email.rcptTo.get(1).name);
+ assertEquals("rcpt2@client.com", email.rcptTo.get(1).email);
+ }
+
+
+ /**
+ * Tests that RCPT TO recipients can be added to the email via Recipient objects
+ */
+ @Test
+ public void testRcptToRecipientsWithObjects() {
+
+ Recipient rcpt1 = new Recipient("rcpt name 1", "rcpt1@client.com");
+ Recipient rcpt2 = new Recipient("rcpt name 2", "rcpt2@client.com");
+
+ Email email = TestHelper.createBasicEmail(false);
+
+ email.addRcptTo(rcpt1);
+
+ assertEquals(1, email.rcptTo.size());
+ assertEquals(rcpt1.name, email.rcptTo.get(0).name);
+ assertEquals(rcpt1.email, email.rcptTo.get(0).email);
+
+ email.addRcptTo(rcpt2);
+
+ assertEquals(2, email.rcptTo.size());
+ assertEquals(rcpt2.name, email.rcptTo.get(1).name);
+ assertEquals(rcpt2.email, email.rcptTo.get(1).email);
+ }
+
+
+ /**
+ * Tests that rcptTo field serializes correctly as "rcpt_to" in JSON
+ */
+ @Test
+ public void testRcptToSerialization() {
+
+ Email email = TestHelper.createBasicEmail(true);
+
+ email.addRcptTo("rcpt name", "rcpt@client.com");
+
+ String json = email.serializeForSending();
+
+ assertTrue(json.contains("\"rcpt_to\""));
+ assertTrue(json.contains("rcpt@client.com"));
+ }
+
+
+ /**
+ * Tests that the camelCase addCc method works the same as AddCc
+ */
+ @Test
+ public void testCamelCaseAddCc() {
+
+ Recipient ccRecipient = new Recipient("cc name", "cc@test.com");
+
+ Email email = TestHelper.createBasicEmail(false);
+
+ email.addCc(ccRecipient.name, ccRecipient.email);
+
+ assertEquals(1, email.cc.size());
+ assertEquals(ccRecipient.name, email.cc.get(0).name);
+ assertEquals(ccRecipient.email, email.cc.get(0).email);
+
+ Email email2 = TestHelper.createBasicEmail(false);
+ email2.addCc(ccRecipient);
+
+ assertEquals(1, email2.cc.size());
+ assertEquals(ccRecipient.name, email2.cc.get(0).name);
+ }
+
+
+ /**
+ * Tests that the camelCase addBcc method works the same as AddBcc
+ */
+ @Test
+ public void testCamelCaseAddBcc() {
+
+ Recipient bccRecipient = new Recipient("bcc name", "bcc@test.com");
+
+ Email email = TestHelper.createBasicEmail(false);
+
+ email.addBcc(bccRecipient.name, bccRecipient.email);
+
+ assertEquals(1, email.bcc.size());
+ assertEquals(bccRecipient.name, email.bcc.get(0).name);
+ assertEquals(bccRecipient.email, email.bcc.get(0).email);
+
+ Email email2 = TestHelper.createBasicEmail(false);
+ email2.addBcc(bccRecipient);
+
+ assertEquals(1, email2.bcc.size());
+ assertEquals(bccRecipient.name, email2.bcc.get(0).name);
+ }
+
+
+ /**
+ * Tests that the camelCase addReplyTo method works correctly
+ */
+ @Test
+ public void testCamelCaseAddReplyTo() {
+
+ Email email = TestHelper.createBasicEmail(false);
+
+ email.addReplyTo("reply name", "reply@test.com");
+
+ assertEquals("reply name", email.replyTo.name);
+ assertEquals("reply@test.com", email.replyTo.email);
+
+ Recipient replyToRecipient = new Recipient("reply name 2", "reply2@test.com");
+ email.addReplyTo(replyToRecipient);
+
+ assertEquals("reply name 2", email.replyTo.name);
+ assertEquals("reply2@test.com", email.replyTo.email);
+ }
}
diff --git a/src/test/java/com/mailersend/sdk/tests/EmailSendTest.java b/src/test/java/com/mailersend/sdk/tests/EmailSendTest.java
index eb71c26..b5a6ef1 100644
--- a/src/test/java/com/mailersend/sdk/tests/EmailSendTest.java
+++ b/src/test/java/com/mailersend/sdk/tests/EmailSendTest.java
@@ -13,11 +13,15 @@
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
+import java.util.stream.Stream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.Recipient;
@@ -51,7 +55,7 @@ public void afterEach() throws IOException
* Test token
*/
@Test
- public void TestInvalidTokenFailsWith401() {
+ public void testInvalidTokenFailsWith401() {
Email email = new Email();
@@ -69,7 +73,7 @@ public void TestInvalidTokenFailsWith401() {
* Test wrong personalization
*/
@Test
- public void TestInvalidPersonalization() {
+ public void testInvalidPersonalization() {
Email email = TestHelper.createBasicEmail(false);
@@ -91,7 +95,7 @@ public void TestInvalidPersonalization() {
* Simple email send
*/
@Test
- public void TestSimpleSend() throws MailerSendException {
+ public void testSimpleSend() throws MailerSendException {
Email email = new Email();
@@ -116,7 +120,7 @@ public void TestSimpleSend() throws MailerSendException {
* Test personalization from a POJO
*/
@Test
- public void TestPojoPersonalization() throws MailerSendException {
+ public void testPojoPersonalization() throws MailerSendException {
Email email = TestHelper.createBasicEmail(false);
@@ -135,7 +139,7 @@ public void TestPojoPersonalization() throws MailerSendException {
* Test email with CC
*/
@Test
- public void TestCcSend() throws MailerSendException {
+ public void testCcSend() throws MailerSendException {
Email email = TestHelper.createBasicEmail(false);
@@ -152,7 +156,7 @@ public void TestCcSend() throws MailerSendException {
* Test email with BCC
*/
@Test
- public void TestBccSend() throws MailerSendException {
+ public void testBccSend() throws MailerSendException {
Email email = TestHelper.createBasicEmail(false);
@@ -169,7 +173,7 @@ public void TestBccSend() throws MailerSendException {
* Test email with attachment
*/
@Test
- public void TestEmailWithAttachment() throws IOException, MailerSendException {
+ public void testEmailWithAttachment() throws IOException, MailerSendException {
Email email = TestHelper.createBasicEmail(true);
@@ -186,7 +190,7 @@ public void TestEmailWithAttachment() throws IOException, MailerSendException {
* Test bulk email send
*/
@Test
- public void TestSendBulkEmail() throws MailerSendException {
+ public void testSendBulkEmail() throws MailerSendException {
Email email = TestHelper.createBasicEmail(true);
Email email2 = TestHelper.createBasicEmail(true);
@@ -206,7 +210,7 @@ public void TestSendBulkEmail() throws MailerSendException {
* Test retrieving the status for a bulk send
*/
@Test
- public void TestBulkSendStatus() throws MailerSendException {
+ public void testBulkSendStatus() throws MailerSendException {
Email email = TestHelper.createBasicEmail(true);
Email email2 = TestHelper.createBasicEmail(true);
@@ -221,17 +225,143 @@ public void TestBulkSendStatus() throws MailerSendException {
assertEquals(QUEUED, ms.emails().bulkSendStatus(bulkSendId).state);
}
+ /**
+ * Tests that sending an email missing a required field fails with 422
+ */
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("missingRequiredFieldEmails")
+ public void testSendEmailMissingRequiredFieldFails(String label, Email email) {
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.emails().send(email);
+ });
+ assertEquals(422, e.code);
+ }
+
+ static Stream missingRequiredFieldEmails() {
+ Email withoutFrom = new Email();
+ withoutFrom.addRecipient(TestHelper.toName, TestHelper.toEmail);
+ withoutFrom.setSubject(TestHelper.subject);
+ withoutFrom.setHtml(TestHelper.html);
+ withoutFrom.setPlain(TestHelper.text);
+
+ Email withoutTo = new Email();
+ withoutTo.setFrom(TestHelper.fromName, TestHelper.emailFrom);
+ withoutTo.setSubject(TestHelper.subject);
+ withoutTo.setHtml(TestHelper.html);
+ withoutTo.setPlain(TestHelper.text);
+
+ Email withoutSubject = new Email();
+ withoutSubject.setFrom(TestHelper.fromName, TestHelper.emailFrom);
+ withoutSubject.addRecipient(TestHelper.toName, TestHelper.toEmail);
+ withoutSubject.setHtml(TestHelper.html);
+ withoutSubject.setPlain(TestHelper.text);
+
+ Email withoutBody = new Email();
+ withoutBody.setFrom(TestHelper.fromName, TestHelper.emailFrom);
+ withoutBody.addRecipient(TestHelper.toName, TestHelper.toEmail);
+ withoutBody.setSubject(TestHelper.subject);
+
+ return Stream.of(
+ Arguments.of("missing from", withoutFrom),
+ Arguments.of("missing to", withoutTo),
+ Arguments.of("missing subject", withoutSubject),
+ Arguments.of("missing body", withoutBody)
+ );
+ }
+
+
+ /**
+ * Test send email with custom headers returns 202
+ */
@Test
- public void ScheduleEmailTest() throws MailerSendException {
+ public void testSendEmailWithHeaders() throws MailerSendException {
Email email = new Email();
-
+ email.setFrom(TestHelper.fromName, TestHelper.emailFrom);
+ email.addRecipient(TestHelper.toName, TestHelper.toEmail);
+ email.setSubject(TestHelper.subject);
+ email.setHtml(TestHelper.html);
+ email.setPlain(TestHelper.text);
+ email.addHeader("X-Custom-Header", "custom-value");
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ assertEquals(202, ms.emails().send(email).responseStatusCode);
+ }
+
+
+ /**
+ * Test send email with precedence_bulk set to true returns 202
+ */
+ @Test
+ public void testSendEmailWithPrecedenceBulk() throws MailerSendException {
+ Email email = new Email();
+ email.setFrom(TestHelper.fromName, TestHelper.emailFrom);
+ email.addRecipient(TestHelper.toName, TestHelper.toEmail);
+ email.setSubject(TestHelper.subject);
+ email.setHtml(TestHelper.html);
+ email.setPlain(TestHelper.text);
+ email.setPrecedenceBulk(true);
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ assertEquals(202, ms.emails().send(email).responseStatusCode);
+ }
+
+
+ /**
+ * Test send email with list_unsubscribe returns 202
+ */
+ @Test
+ public void testSendEmailWithListUnsubscribe() throws MailerSendException {
+ Email email = new Email();
+ email.setFrom(TestHelper.fromName, TestHelper.emailFrom);
+ email.addRecipient(TestHelper.toName, TestHelper.toEmail);
+ email.setSubject(TestHelper.subject);
+ email.setHtml(TestHelper.html);
+ email.setPlain(TestHelper.text);
+ email.setListUnsubscribe("https://unsubscribe.example.com");
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ assertEquals(202, ms.emails().send(email).responseStatusCode);
+ }
+
+
+ /**
+ * Test bulk send status response has all expected fields
+ */
+ @Test
+ public void testBulkSendStatusHasAllFields() throws MailerSendException {
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ com.mailersend.sdk.emails.BulkSendStatus status = ms.emails().bulkSendStatus("known-bulk-send-id");
+
+ assertNotNull(status.state);
+ assertNotNull(status.id);
+ assertTrue(status.id.length() > 0);
+ assertTrue(status.totalRecipientsCount >= 0);
+ assertNotNull(status.createdAt);
+ }
+
+
+ @Test
+ public void scheduleEmailTest() throws MailerSendException {
+ Email email = new Email();
+
email.subject = TestHelper.subject;
email.html = TestHelper.html;
email.text = TestHelper.text;
-
+
email.addRecipient(TestHelper.toName, TestHelper.toEmail);
email.AddReplyTo(new Recipient(TestHelper.fromName, TestHelper.emailFrom));
-
+
email.setFrom(TestHelper.fromName, TestHelper.emailFrom);
TemporalAccessor ta = DateTimeFormatter.ISO_INSTANT.parse("2024-08-03T00:00:00.875000Z");
diff --git a/src/test/java/com/mailersend/sdk/tests/EmailVerificationTests.java b/src/test/java/com/mailersend/sdk/tests/EmailVerificationTests.java
index 4dbda30..c40a4dd 100644
--- a/src/test/java/com/mailersend/sdk/tests/EmailVerificationTests.java
+++ b/src/test/java/com/mailersend/sdk/tests/EmailVerificationTests.java
@@ -1,6 +1,8 @@
package com.mailersend.sdk.tests;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
@@ -13,9 +15,11 @@
import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.exceptions.MailerSendException;
import com.mailersend.sdk.vcr.VcrRecorder;
-import com.mailsend.sdk.emailverification.EmailVerificationList;
-import com.mailsend.sdk.emailverification.EmailVerificationLists;
-import com.mailsend.sdk.emailverification.ListVerificationResults;
+import com.mailersend.sdk.emailverification.AsyncEmailVerificationResponse;
+import com.mailersend.sdk.emailverification.EmailVerificationList;
+import com.mailersend.sdk.emailverification.EmailVerificationLists;
+import com.mailersend.sdk.emailverification.ListVerificationResults;
+import com.mailersend.sdk.emailverification.SingleEmailVerificationResponse;
public class EmailVerificationTests {
@@ -32,7 +36,7 @@ public void afterEach() throws IOException
}
@Test
- public void CreateVerificationListTest() {
+ public void createVerificationListTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -56,7 +60,7 @@ public void CreateVerificationListTest() {
}
@Test
- public void VerifyListTest() {
+ public void verifyListTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -75,7 +79,7 @@ public void VerifyListTest() {
}
@Test
- public void GetListTest() {
+ public void getListTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -95,7 +99,7 @@ public void GetListTest() {
@Test
- public void GetListResultsTest() {
+ public void getListResultsTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -111,18 +115,236 @@ public void GetListResultsTest() {
@Test
- public void GetListsTest() {
+ public void getListsTest() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
EmailVerificationLists lists = ms.emailVerification().getLists();
-
+
assertEquals(lists.lists[0].source, "api");
-
+
} catch (MailerSendException e) {
-
+
fail();
}
}
+
+ /**
+ * Behavior: POST /email-verification/verify returns the status field.
+ */
+ @Test
+ public void testVerifyEmailReturnsStatus() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SingleEmailVerificationResponse response = ms.emailVerification().verifyEmail("test@example.com");
+
+ assertNotNull(response);
+ assertEquals("valid", response.status);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ /**
+ * Validation: null email rejected before any HTTP call is made.
+ */
+ @Test
+ public void testVerifyEmailWithNullThrowsException() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.emailVerification().verifyEmail(null);
+ });
+
+ assertEquals("Email cannot be null or empty", ex.getMessage());
+ }
+
+ /**
+ * Validation: empty email rejected before any HTTP call is made.
+ */
+ @Test
+ public void testVerifyEmailWithEmptyStringThrowsException() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.emailVerification().verifyEmail("");
+ });
+
+ assertEquals("Email cannot be null or empty", ex.getMessage());
+ }
+
+ /**
+ * Failure mode: invalid token results in a 401 exception for verifyEmail.
+ */
+ @Test
+ public void testVerifyEmailWithInvalidTokenThrows401() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.invalidToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.emailVerification().verifyEmail("test@example.com");
+ });
+
+ assertEquals(401, ex.code);
+ }
+
+ /**
+ * Behavior: POST /email-verification/verify-async returns id, address, status, result, error.
+ */
+ @Test
+ public void testVerifyEmailAsyncReturnsResponseFields() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ AsyncEmailVerificationResponse response = ms.emailVerification().verifyEmailAsync("test@example.com");
+
+ assertNotNull(response);
+ assertEquals("67c83bf24a5d02568029ee10", response.id);
+ assertEquals("test@example.com", response.address);
+ assertEquals("queued", response.status);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ /**
+ * Validation: null email rejected before any HTTP call is made for async verify.
+ */
+ @Test
+ public void testVerifyEmailAsyncWithNullThrowsException() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.emailVerification().verifyEmailAsync(null);
+ });
+
+ assertEquals("Email cannot be null or empty", ex.getMessage());
+ }
+
+ /**
+ * Validation: empty email rejected before any HTTP call is made for async verify.
+ */
+ @Test
+ public void testVerifyEmailAsyncWithEmptyStringThrowsException() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.emailVerification().verifyEmailAsync("");
+ });
+
+ assertEquals("Email cannot be null or empty", ex.getMessage());
+ }
+
+ /**
+ * Failure mode: invalid token results in a 401 exception for verifyEmailAsync.
+ */
+ @Test
+ public void testVerifyEmailAsyncWithInvalidTokenThrows401() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.invalidToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.emailVerification().verifyEmailAsync("test@example.com");
+ });
+
+ assertEquals(401, ex.code);
+ }
+
+ /**
+ * Behavior: GET /email-verification/verify-async/{id} returns id, address, status, result, error.
+ */
+ @Test
+ public void testGetVerifyEmailAsyncStatusReturnsResponseFields() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ AsyncEmailVerificationResponse response = ms.emailVerification().getVerifyEmailAsyncStatus("abc123asyncstatusid");
+
+ assertNotNull(response);
+ assertEquals("abc123asyncstatusid", response.id);
+ assertEquals("test@example.com", response.address);
+ assertEquals("completed", response.status);
+ assertEquals("unknown", response.result);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ /**
+ * Validation: null id rejected before any HTTP call is made.
+ */
+ @Test
+ public void testGetVerifyEmailAsyncStatusWithNullThrowsException() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.emailVerification().getVerifyEmailAsyncStatus(null);
+ });
+
+ assertEquals("Verification ID cannot be null or empty", ex.getMessage());
+ }
+
+ /**
+ * Validation: empty id rejected before any HTTP call is made.
+ */
+ @Test
+ public void testGetVerifyEmailAsyncStatusWithEmptyStringThrowsException() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.emailVerification().getVerifyEmailAsyncStatus("");
+ });
+
+ assertEquals("Verification ID cannot be null or empty", ex.getMessage());
+ }
+
+ /**
+ * Failure mode: invalid id results in a 404 exception for getVerifyEmailAsyncStatus.
+ */
+ @Test
+ public void testGetVerifyEmailAsyncStatusWithInvalidIdThrows404() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.emailVerification().getVerifyEmailAsyncStatus("invalid-async-id-404");
+ });
+
+ assertEquals(404, ex.code);
+ }
}
diff --git a/src/test/java/com/mailersend/sdk/tests/InboundRoutesTest.java b/src/test/java/com/mailersend/sdk/tests/InboundRoutesTest.java
index 226fea2..50cdcb3 100644
--- a/src/test/java/com/mailersend/sdk/tests/InboundRoutesTest.java
+++ b/src/test/java/com/mailersend/sdk/tests/InboundRoutesTest.java
@@ -1,140 +1,639 @@
package com.mailersend.sdk.tests;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
+import java.util.stream.Stream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.exceptions.MailerSendException;
+import com.mailersend.sdk.inboundroutes.CatchFilter;
+import com.mailersend.sdk.inboundroutes.Filter;
import com.mailersend.sdk.inboundroutes.Forward;
+import com.mailersend.sdk.inboundroutes.InboundFilter;
import com.mailersend.sdk.inboundroutes.InboundRoute;
import com.mailersend.sdk.inboundroutes.InboundRoutesList;
import com.mailersend.sdk.vcr.VcrRecorder;
public class InboundRoutesTest {
- @BeforeEach
- public void setupEach(TestInfo info) throws IOException
- {
- VcrRecorder.useRecording("InboundRoutesTest_" + info.getDisplayName());
- }
-
- @AfterEach
- public void afterEach() throws IOException
- {
- VcrRecorder.stopRecording();
- }
-
-
- @Test
- public void AddInboundRouteTest() {
-
- MailerSend ms = new MailerSend();
- ms.setToken(TestHelper.validToken);
-
+ @BeforeEach
+ public void setupEach(TestInfo info) throws IOException
+ {
+ VcrRecorder.useRecording("InboundRoutesTest_" + info.getDisplayName());
+ }
+
+ @AfterEach
+ public void afterEach() throws IOException
+ {
+ VcrRecorder.stopRecording();
+ }
+
+ @Test
+ public void addInboundRouteTest() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
try {
-
- Forward forward = new Forward();
- forward.type = "webhook";
- forward.value = "https://example-domain.com";
- forward.secret = "asdfgh";
-
- ms.inboundRoutes().builder()
- .domainId(TestHelper.domainId)
- .name("Test inbound name")
- .domainEnabled(false)
- .matchFilter("match_all")
- .forwards(new Forward[] { forward })
- .addRoute();
-
+
+ Forward forward = new Forward();
+ forward.type = "webhook";
+ forward.value = "https://example-domain.com";
+ forward.secret = "asdfgh";
+
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .name("Test inbound name")
+ .domainEnabled(false)
+ .matchFilter("match_all")
+ .forwards(new Forward[] { forward })
+ .addRoute();
+
} catch (MailerSendException ex) {
- fail();
+ fail();
+ }
+ }
+
+ @Test
+ public void inboundRoutesListTest() {
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+ InboundRoutesList routes = ms.inboundRoutes().getRoutes();
+
+ assertEquals(routes.responseStatusCode, 200);
+
+ for (InboundRoute route : routes.routes) {
+ System.out.println(route.id);
+ }
+
+ } catch (MailerSendException e) {
+
+ fail();
+ }
+ }
+
+ @Test
+ public void singleInboundRouteTest() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+ InboundRoute route = ms.inboundRoutes().getRoute(TestHelper.inboundRouteId);
+
+ System.out.println(route.id);
+ System.out.println(route.name);
+
+ } catch (MailerSendException e) {
+ fail();
+ }
+ }
+
+ @Test
+ public void updateInboundRouteTest() {
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ Forward forward = new Forward();
+ forward.type = "webhook";
+ forward.value = "https://example.com";
+ forward.secret = "asdfgh";
+
+ InboundRoute route = ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .name("Updated route name")
+ .domainEnabled(false)
+ .matchFilter("match_all")
+ .forwards(new Forward[] { forward })
+ .updateRoute(TestHelper.inboundRouteId);
+
+ assertEquals(route.name, "Updated route name");
+
+ } catch (MailerSendException e) {
+ fail();
+ }
+ }
+
+ @Test
+ public void deleteInboundRouteTest() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+ boolean result = ms.inboundRoutes().deleteRoute(TestHelper.inboundRouteId);
+
+ assertTrue(result);
+ } catch (MailerSendException e) {
+ fail();
+ }
+ }
+
+ @Test
+ public void inbound_domain_required_when_domain_enabled_is_true() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () ->
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(true)
+ // inboundDomain not set
+ .matchFilter("match_all")
+ .addRoute()
+ );
+
+ assertEquals("inbound_domain is required when domain_enabled is true", e.getMessage());
+ }
+
+ @Test
+ public void inbound_domain_not_required_when_domain_enabled_is_false() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .matchFilter("match_all")
+ .addRoute();
+ } catch (MailerSendException e) {
+ fail();
+ }
+ }
+
+ @Test
+ public void inbound_domain_supplied_with_domain_enabled_true_passes_validation() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(true)
+ .inboundDomain("inbound.example.com")
+ .matchFilter("match_all")
+ .addRoute();
+ } catch (MailerSendException e) {
+ if (e.getMessage() != null && e.getMessage().equals("inbound_domain is required when domain_enabled is true")) {
+ fail("Should not throw inbound_domain validation error when domain is supplied");
+ }
+ }
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("invalidPriorityValues")
+ public void inbound_priority_range_validation(String label, int priority, String expectedMessage) {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () ->
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .inboundPriority(priority)
+ .matchFilter("match_all")
+ .addRoute()
+ );
+
+ assertEquals(expectedMessage, e.getMessage());
+ }
+
+ static Stream invalidPriorityValues() {
+ return Stream.of(
+ Arguments.of("inbound_priority_must_not_be_negative", -1, "inbound_priority must be between 0 and 100"),
+ Arguments.of("inbound_priority_must_not_exceed_100", 101, "inbound_priority must be between 0 and 100")
+ );
+ }
+
+ @Test
+ public void inbound_priority_boundary_values_are_valid() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ // 0 and 100 are boundary values — validation must not fire for them
+ for (int boundary : new int[]{0, 100}) {
+ final int p = boundary;
+ try {
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .inboundPriority(p)
+ .matchFilter("match_all")
+ .addRoute();
+ } catch (MailerSendException e) {
+ if (e.getMessage() != null && e.getMessage().equals("inbound_priority must be between 0 and 100")) {
+ fail("Boundary value " + p + " should not fail priority validation");
+ }
+ }
+ }
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("invalidCatchFilterTypes")
+ public void catch_filter_type_enum_validation(String label, String type, String expectedMessage) {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ CatchFilter cf = new CatchFilter();
+ cf.type = type;
+
+ MailerSendException e = assertThrows(MailerSendException.class, () ->
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .catchFilter(cf)
+ .matchFilter("match_all")
+ .addRoute()
+ );
+
+ assertEquals(expectedMessage, e.getMessage());
+ }
+
+ static Stream invalidCatchFilterTypes() {
+ return Stream.of(
+ Arguments.of("catch_filter_type_invalid_value", "invalid_type", "catch_filter.type must be one of: catch_all, catch_recipient"),
+ Arguments.of("catch_filter_type_null", null, "catch_filter.type must be one of: catch_all, catch_recipient"),
+ Arguments.of("catch_filter_type_empty_string", "", "catch_filter.type must be one of: catch_all, catch_recipient")
+ );
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("validCatchFilterTypes")
+ public void catch_filter_valid_type_does_not_throw(String label, String type) {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ CatchFilter cf = new CatchFilter();
+ cf.type = type;
+
+ try {
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .catchFilter(cf)
+ .matchFilter("match_all")
+ .addRoute();
+ } catch (MailerSendException e) {
+ if (e.getMessage() != null && e.getMessage().startsWith("catch_filter.type must be")) {
+ fail("Valid catch_filter.type '" + type + "' should not fail enum validation");
+ }
+ }
+ }
+
+ static Stream validCatchFilterTypes() {
+ return Stream.of(
+ Arguments.of("catch_all_is_valid", "catch_all"),
+ Arguments.of("catch_recipient_is_valid", "catch_recipient")
+ );
+ }
+
+ @Test
+ public void catch_filter_filters_must_not_exceed_5_items() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ Filter[] filters = new Filter[6];
+ for (int i = 0; i < 6; i++) {
+ filters[i] = new Filter();
+ filters[i].comparer = "equal";
+ filters[i].value = "value" + i;
+ }
+
+ CatchFilter cf = new CatchFilter("catch_recipient", filters);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () ->
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .catchFilter(cf)
+ .matchFilter("match_all")
+ .addRoute()
+ );
+
+ assertEquals("catch_filter.filters must not exceed 5 items", e.getMessage());
+ }
+
+ @Test
+ public void catch_filter_5_items_is_at_the_limit_and_valid() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ Filter[] filters = new Filter[5];
+ for (int i = 0; i < 5; i++) {
+ filters[i] = new Filter();
+ filters[i].comparer = "equal";
+ filters[i].value = "value" + i;
+ }
+
+ CatchFilter cf = new CatchFilter("catch_recipient", filters);
+
+ try {
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .catchFilter(cf)
+ .matchFilter("match_all")
+ .addRoute();
+ } catch (MailerSendException e) {
+ if (e.getMessage() != null && e.getMessage().equals("catch_filter.filters must not exceed 5 items")) {
+ fail("5 filters should not fail the max-array-length validation");
+ }
}
- }
-
- @Test
- public void InboundRoutesListTest() {
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("invalidCatchFilterComparers")
+ public void catch_filter_comparer_enum_validation(String label, String comparer, String expectedMessage) {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ Filter filter = new Filter();
+ filter.comparer = comparer;
+ filter.value = "test";
+
+ CatchFilter cf = new CatchFilter("catch_recipient", new Filter[]{filter});
+
+ MailerSendException e = assertThrows(MailerSendException.class, () ->
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .catchFilter(cf)
+ .matchFilter("match_all")
+ .addRoute()
+ );
+
+ assertEquals(expectedMessage, e.getMessage());
+ }
+
+ static Stream invalidCatchFilterComparers() {
+ return Stream.of(
+ Arguments.of("catch_filter_comparer_invalid_value", "like", "catch_filter.filters.comparer must be one of: equal, not-equal, contains, not-contains, starts-with, ends-with, not-starts-with, not-ends-with"),
+ Arguments.of("catch_filter_comparer_arbitrary_string", "EQUAL", "catch_filter.filters.comparer must be one of: equal, not-equal, contains, not-contains, starts-with, ends-with, not-starts-with, not-ends-with")
+ );
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("validComparers")
+ public void catch_filter_valid_comparers_do_not_throw(String label, String comparer) {
+
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
+ Filter filter = new Filter();
+ filter.comparer = comparer;
+ filter.value = "test";
+
+ CatchFilter cf = new CatchFilter("catch_recipient", new Filter[]{filter});
+
try {
- InboundRoutesList routes = ms.inboundRoutes().getRoutes();
-
- assertEquals(routes.responseStatusCode, 200);
-
- for (InboundRoute route : routes.routes) {
- System.out.println(route.id);
- }
-
- } catch (MailerSendException e) {
-
- fail();
- }
- }
-
- @Test
- public void SingleInboundRouteTest() {
-
- MailerSend ms = new MailerSend();
- ms.setToken(TestHelper.validToken);
-
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .catchFilter(cf)
+ .matchFilter("match_all")
+ .addRoute();
+ } catch (MailerSendException e) {
+ if (e.getMessage() != null && e.getMessage().startsWith("catch_filter.filters.comparer must be")) {
+ fail("Valid comparer '" + comparer + "' should not fail enum validation");
+ }
+ }
+ }
+
+ static Stream validComparers() {
+ return Stream.of(
+ Arguments.of("comparer_equal", "equal"),
+ Arguments.of("comparer_not_equal", "not-equal"),
+ Arguments.of("comparer_contains", "contains"),
+ Arguments.of("comparer_not_contains", "not-contains"),
+ Arguments.of("comparer_starts_with", "starts-with"),
+ Arguments.of("comparer_ends_with", "ends-with"),
+ Arguments.of("comparer_not_starts_with", "not-starts-with"),
+ Arguments.of("comparer_not_ends_with", "not-ends-with")
+ );
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("invalidCatchTypes")
+ public void catch_type_enum_validation(String label, String catchType, String expectedMessage) {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () ->
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .catchType(catchType)
+ .matchFilter("match_all")
+ .addRoute()
+ );
+
+ assertEquals(expectedMessage, e.getMessage());
+ }
+
+ static Stream invalidCatchTypes() {
+ return Stream.of(
+ Arguments.of("catch_type_invalid_value", "both", "catch_type must be one of: all, one"),
+ Arguments.of("catch_type_arbitrary_string", "ANY", "catch_type must be one of: all, one")
+ );
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("validCatchTypes")
+ public void catch_type_valid_values_do_not_throw(String label, String catchType) {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
try {
- InboundRoute route = ms.inboundRoutes().getRoute(TestHelper.inboundRouteId);
-
- System.out.println(route.id);
- System.out.println(route.name);
-
- } catch (MailerSendException e) {
- fail();
- }
- }
-
- @Test
- public void UpdateInboundRouteTest() {
- MailerSend ms = new MailerSend();
- ms.setToken(TestHelper.validToken);
-
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .catchType(catchType)
+ .matchFilter("match_all")
+ .addRoute();
+ } catch (MailerSendException e) {
+ if (e.getMessage() != null && e.getMessage().startsWith("catch_type must be")) {
+ fail("Valid catch_type '" + catchType + "' should not fail enum validation");
+ }
+ }
+ }
+
+ static Stream validCatchTypes() {
+ return Stream.of(
+ Arguments.of("catch_type_all", "all"),
+ Arguments.of("catch_type_one", "one")
+ );
+ }
+
+ @Test
+ public void match_filter_key_required_when_type_is_match_header() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ InboundFilter filter = new InboundFilter("equal", "X-Custom-Header-Value");
+ // key intentionally not set
+
+ MailerSendException e = assertThrows(MailerSendException.class, () ->
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .matchFilter("match_header", new InboundFilter[]{filter})
+ .addRoute()
+ );
+
+ assertEquals("match_filter.filters.key is required when match_filter.type is match_header", e.getMessage());
+ }
+
+ @Test
+ public void match_filter_key_not_required_when_type_is_not_match_header() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ InboundFilter filter = new InboundFilter("equal", "sender@example.com");
+ // key not set — should be fine for match_sender
+
try {
-
- Forward forward = new Forward();
- forward.type = "webhook";
- forward.value = "https://example.com";
- forward.secret = "asdfgh";
-
- InboundRoute route = ms.inboundRoutes().builder()
- .domainId(TestHelper.domainId)
- .name("Updated route name")
- .domainEnabled(false)
- .matchFilter("match_all")
- .forwards(new Forward[] { forward })
- .updateRoute(TestHelper.inboundRouteId);
-
- assertEquals(route.name, "Updated route name");
-
- } catch (MailerSendException e) {
- fail();
- }
- }
-
- @Test
- public void DeleteInboundRouteTest() {
-
- MailerSend ms = new MailerSend();
- ms.setToken(TestHelper.validToken);
-
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .matchFilter("match_sender", new InboundFilter[]{filter})
+ .addRoute();
+ } catch (MailerSendException e) {
+ if (e.getMessage() != null && e.getMessage().equals("match_filter.filters.key is required when match_filter.type is match_header")) {
+ fail("key should not be required for match_sender type");
+ }
+ }
+ }
+
+ @Test
+ public void match_filter_key_supplied_with_match_header_passes_validation() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ InboundFilter filter = new InboundFilter("equal", "X-Custom-Header-Value", "X-Custom-Header");
+
try {
- boolean result = ms.inboundRoutes().deleteRoute(TestHelper.inboundRouteId);
-
- assertTrue(result);
- } catch (MailerSendException e) {
- fail();
- }
- }
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .matchFilter("match_header", new InboundFilter[]{filter})
+ .addRoute();
+ } catch (MailerSendException e) {
+ if (e.getMessage() != null && e.getMessage().equals("match_filter.filters.key is required when match_filter.type is match_header")) {
+ fail("Should not throw key validation error when key is supplied");
+ }
+ }
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("invalidMatchFilterComparers")
+ public void match_filter_comparer_enum_validation(String label, String comparer, String expectedMessage) {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ InboundFilter filter = new InboundFilter(comparer, "value", "X-Header");
+
+ MailerSendException e = assertThrows(MailerSendException.class, () ->
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .matchFilter("match_header", new InboundFilter[]{filter})
+ .addRoute()
+ );
+
+ assertEquals(expectedMessage, e.getMessage());
+ }
+
+ static Stream invalidMatchFilterComparers() {
+ return Stream.of(
+ Arguments.of("match_filter_comparer_invalid_value", "like", "match_filter.filters.comparer must be one of: equal, not-equal, contains, not-contains, starts-with, ends-with, not-starts-with, not-ends-with"),
+ Arguments.of("match_filter_comparer_arbitrary_string", "CONTAINS", "match_filter.filters.comparer must be one of: equal, not-equal, contains, not-contains, starts-with, ends-with, not-starts-with, not-ends-with")
+ );
+ }
+
+ @Test
+ public void update_route_also_validates_inbound_domain_when_domain_enabled_is_true() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () ->
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(true)
+ .matchFilter("match_all")
+ .updateRoute(TestHelper.inboundRouteId)
+ );
+
+ assertEquals("inbound_domain is required when domain_enabled is true", e.getMessage());
+ }
+
+ @Test
+ public void update_route_also_validates_inbound_priority_range() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () ->
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .inboundPriority(200)
+ .matchFilter("match_all")
+ .updateRoute(TestHelper.inboundRouteId)
+ );
+
+ assertEquals("inbound_priority must be between 0 and 100", e.getMessage());
+ }
+
+ @Test
+ public void update_route_also_validates_catch_type_enum() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () ->
+ ms.inboundRoutes().builder()
+ .domainId(TestHelper.domainId)
+ .domainEnabled(false)
+ .catchType("invalid")
+ .matchFilter("match_all")
+ .updateRoute(TestHelper.inboundRouteId)
+ );
+
+ assertEquals("catch_type must be one of: all, one", e.getMessage());
+ }
}
diff --git a/src/test/java/com/mailersend/sdk/tests/MessagesTest.java b/src/test/java/com/mailersend/sdk/tests/MessagesTest.java
index e84a7a8..5cef26e 100644
--- a/src/test/java/com/mailersend/sdk/tests/MessagesTest.java
+++ b/src/test/java/com/mailersend/sdk/tests/MessagesTest.java
@@ -41,7 +41,7 @@ public void afterEach() throws IOException
* Gets a lists of messages
*/
@Test
- public void TestMessagesRetrieval() {
+ public void testMessagesRetrieval() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -67,7 +67,7 @@ public void TestMessagesRetrieval() {
* Tests a single message retrieval
*/
@Test
- public void TestSingleMessage() {
+ public void testSingleMessage() {
// get a single message first
MailerSend ms = new MailerSend();
diff --git a/src/test/java/com/mailersend/sdk/tests/RecipientsTest.java b/src/test/java/com/mailersend/sdk/tests/RecipientsTest.java
index ec657cf..c3d8054 100644
--- a/src/test/java/com/mailersend/sdk/tests/RecipientsTest.java
+++ b/src/test/java/com/mailersend/sdk/tests/RecipientsTest.java
@@ -45,7 +45,7 @@ public void afterEach() throws IOException
* Gets a lists of recipients
*/
@Test
- public void TestRecipientsRetrievall() {
+ public void testRecipientsRetrievall() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -72,7 +72,7 @@ public void TestRecipientsRetrievall() {
* Gets a single recipient
*/
@Test
- public void TestSingleRecipientRetrieval() {
+ public void testSingleRecipientRetrieval() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -104,7 +104,7 @@ public void TestSingleRecipientRetrieval() {
* Deletes a recipient
*/
@Test
- public void TestDeleteRecipient() {
+ public void testDeleteRecipient() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
diff --git a/src/test/java/com/mailersend/sdk/tests/RecpientsSuppressionListsTest.java b/src/test/java/com/mailersend/sdk/tests/RecpientsSuppressionListsTest.java
index e5369ab..d08b85c 100644
--- a/src/test/java/com/mailersend/sdk/tests/RecpientsSuppressionListsTest.java
+++ b/src/test/java/com/mailersend/sdk/tests/RecpientsSuppressionListsTest.java
@@ -1,12 +1,14 @@
/*************************************************
* MailerSend Java SDK
* https://github.com/mailersend/mailersend-java
- *
+ *
* @author MailerSend
* https://mailersend.com
**************************************************/
package com.mailersend.sdk.tests;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
@@ -23,6 +25,7 @@
import com.mailersend.sdk.recipients.BlocklistListResponse;
import com.mailersend.sdk.recipients.SuppressionItem;
import com.mailersend.sdk.recipients.SuppressionList;
+import com.mailersend.sdk.util.ApiRecipientsList;
import com.mailersend.sdk.vcr.VcrRecorder;
public class RecpientsSuppressionListsTest {
@@ -44,7 +47,7 @@ public void afterEach() throws IOException
* Tests retrieving items from the suppression lists
*/
@Test
- public void TestGetFromSuppressionLists() {
+ public void testGetFromSuppressionLists() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -96,7 +99,7 @@ public void TestGetFromSuppressionLists() {
* Tests adding items to the suppression lists
*/
@Test
- public void TestAddToSuppressionList() {
+ public void testAddToSuppressionList() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -160,7 +163,7 @@ public void TestAddToSuppressionList() {
* @throws MailerSendException
*/
@Test
- public void TestDeleteFromSuppressionList() throws MailerSendException {
+ public void testDeleteFromSuppressionList() throws MailerSendException {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -211,4 +214,361 @@ public void TestDeleteFromSuppressionList() throws MailerSendException {
fail();
}
}
+
+
+ // -------------------------------------------------------------------------
+ // Behavior: GET /v1/recipients — query-string parameters
+ // -------------------------------------------------------------------------
+
+ /**
+ * [Behavior] page, limit, and domain_id are serialised into the recipients query string.
+ */
+ @Test
+ public void testGetRecipientsWithPageLimitAndDomainIdParams() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ ApiRecipientsList list = ms.recipients()
+ .page(2)
+ .limit(10)
+ .domainId(TestHelper.domainId)
+ .getRecipients();
+
+ // The fixture returns one recipient — a non-null list proves the URL was built correctly.
+ if (list == null) {
+ fail();
+ }
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ // -------------------------------------------------------------------------
+ // Validation: GET /v1/recipients — limit range
+ // -------------------------------------------------------------------------
+
+ /**
+ * [Validation] limit() throws when the value is below the minimum of 10.
+ */
+ @Test
+ public void testLimitBelowMinimumThrowsValidationException() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.recipients().limit(9);
+ });
+
+ assertEquals("Limit must be between 10 and 100", e.getMessage());
+ }
+
+
+ /**
+ * [Validation] limit() throws when the value exceeds the maximum of 100.
+ */
+ @Test
+ public void testLimitAboveMaximumThrowsValidationException() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.recipients().limit(101);
+ });
+
+ assertEquals("Limit must be between 10 and 100", e.getMessage());
+ }
+
+
+ // -------------------------------------------------------------------------
+ // Validation: POST suppression lists — recipients array required
+ // -------------------------------------------------------------------------
+
+ /**
+ * [Validation] addRecipientsToHardBounces() throws when no recipients have been added.
+ */
+ @Test
+ public void testAddToHardBouncesWithoutRecipientsThrowsException() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.recipients().suppressions().addBuilder().domainId(TestHelper.domainId);
+ ms.recipients().suppressions().addBuilder().addRecipientsToHardBounces();
+ });
+
+ assertEquals("No recipients specified for suppression list", e.getMessage());
+ }
+
+
+ /**
+ * [Validation] addRecipientsToSpamComplaints() throws when no recipients have been added.
+ */
+ @Test
+ public void testAddToSpamComplaintsWithoutRecipientsThrowsException() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.recipients().suppressions().addBuilder().domainId(TestHelper.domainId);
+ ms.recipients().suppressions().addBuilder().addRecipientsToSpamComplaints();
+ });
+
+ assertEquals("No recipients specified for suppression list", e.getMessage());
+ }
+
+
+ /**
+ * [Validation] addRecipientsToUnsubscribes() throws when no recipients have been added.
+ */
+ @Test
+ public void testAddToUnsubscribesWithoutRecipientsThrowsException() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.recipients().suppressions().addBuilder().domainId(TestHelper.domainId);
+ ms.recipients().suppressions().addBuilder().addRecipientsToUnsubscribes();
+ });
+
+ assertEquals("No recipients specified for suppression list", e.getMessage());
+ }
+
+
+ // -------------------------------------------------------------------------
+ // Behavior: DELETE hard-bounces
+ // -------------------------------------------------------------------------
+
+ /**
+ * [Behavior] deleteHardBouncesItems() succeeds when called with a valid item ID.
+ */
+ @Test
+ public void testDeleteHardBouncesItems() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SuppressionList hardBounces = ms.recipients().suppressions().getHardBounces();
+
+ if (hardBounces.items.length == 0) {
+ fail();
+ }
+
+ String itemId = hardBounces.items[0].id;
+
+ MailerSendResponse response = ms.recipients().suppressions()
+ .deleteHardBouncesItems(new String[]{ itemId });
+
+ System.out.println(response.responseStatusCode);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * [Behavior] deleteHardBouncesAllItems() succeeds and returns a 200 status code.
+ */
+ @Test
+ public void testDeleteHardBouncesAllItems() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ MailerSendResponse response = ms.recipients().suppressions().deleteHardBouncesAllItems();
+
+ System.out.println(response.responseStatusCode);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ // -------------------------------------------------------------------------
+ // Behavior: DELETE unsubscribes
+ // -------------------------------------------------------------------------
+
+ /**
+ * [Behavior] deleteUnsubscribesItems() succeeds when called with a valid item ID.
+ */
+ @Test
+ public void testDeleteUnsubscribesItems() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SuppressionList unsubscribes = ms.recipients().suppressions().getUnsubscribes();
+
+ if (unsubscribes.items.length == 0) {
+ fail();
+ }
+
+ String itemId = unsubscribes.items[0].id;
+
+ MailerSendResponse response = ms.recipients().suppressions()
+ .deleteUnsubscribesItems(new String[]{ itemId });
+
+ System.out.println(response.responseStatusCode);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * [Behavior] deleteUnsubscribesAllItems() succeeds and returns a 200 status code.
+ */
+ @Test
+ public void testDeleteUnsubscribesAllItems() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ MailerSendResponse response = ms.recipients().suppressions().deleteUnsubscribesAllItems();
+
+ System.out.println(response.responseStatusCode);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ // -------------------------------------------------------------------------
+ // Behavior: DELETE on-hold-list
+ // -------------------------------------------------------------------------
+
+ /**
+ * [Behavior] deleteOnHoldListItems() succeeds when called with a valid item ID.
+ */
+ @Test
+ public void testDeleteOnHoldListItems() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SuppressionList onHoldList = ms.recipients().suppressions().getOnHoldList();
+
+ if (onHoldList.items.length == 0) {
+ fail();
+ }
+
+ String itemId = onHoldList.items[0].id;
+
+ MailerSendResponse response = ms.recipients().suppressions()
+ .deleteOnHoldListItems(new String[]{ itemId });
+
+ System.out.println(response.responseStatusCode);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * [Behavior] deleteOnHoldListAllItems() succeeds and returns a 200 status code.
+ */
+ @Test
+ public void testDeleteOnHoldListAllItems() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ MailerSendResponse response = ms.recipients().suppressions().deleteOnHoldListAllItems();
+
+ System.out.println(response.responseStatusCode);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ // -------------------------------------------------------------------------
+ // Behavior: DELETE all variants — blocklist and spam-complaints
+ // -------------------------------------------------------------------------
+
+ /**
+ * [Behavior] deleteBlocklistAllItems() succeeds and returns a 200 status code.
+ */
+ @Test
+ public void testDeleteBlocklistAllItems() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ MailerSendResponse response = ms.recipients().suppressions().deleteBlocklistAllItems();
+
+ System.out.println(response.responseStatusCode);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * [Behavior] deleteSpamComplaintsAllItems() succeeds and returns a 200 status code.
+ */
+ @Test
+ public void testDeleteSpamComplaintsAllItems() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ MailerSendResponse response = ms.recipients().suppressions().deleteSpamComplaintsAllItems();
+
+ System.out.println(response.responseStatusCode);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
}
diff --git a/src/test/java/com/mailersend/sdk/tests/ScheduledMessagesTest.java b/src/test/java/com/mailersend/sdk/tests/ScheduledMessagesTest.java
new file mode 100644
index 0000000..37c0748
--- /dev/null
+++ b/src/test/java/com/mailersend/sdk/tests/ScheduledMessagesTest.java
@@ -0,0 +1,157 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.tests;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+
+import com.mailersend.sdk.MailerSend;
+import com.mailersend.sdk.exceptions.MailerSendException;
+import com.mailersend.sdk.scheduledmessages.ScheduledMessage;
+import com.mailersend.sdk.scheduledmessages.ScheduledMessages;
+import com.mailersend.sdk.scheduledmessages.ScheduledMessagesList;
+import com.mailersend.sdk.vcr.VcrRecorder;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+
+public class ScheduledMessagesTest {
+
+ @BeforeEach
+ public void setupEach(TestInfo info) throws IOException {
+ VcrRecorder.useRecording("ScheduledMessagesTest_" + info.getDisplayName());
+ }
+
+ @AfterEach
+ public void afterEach() throws IOException {
+ VcrRecorder.stopRecording();
+ }
+
+
+ /**
+ * GET /v1/message-schedules returns a list with pagination
+ */
+ @Test
+ public void testCanGetScheduledMessages() throws MailerSendException {
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ ScheduledMessagesList list = ms.scheduledMessages().getScheduledMessages();
+
+ assertNotNull(list);
+ assertNotNull(list.scheduledMessages);
+ assertNotNull(list.meta);
+ }
+
+
+ /**
+ * GET /v1/message-schedules with domainId, page, limit, and status filters applied
+ */
+ @Test
+ public void testCanGetScheduledMessagesWithFilters() throws MailerSendException {
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ ScheduledMessagesList list = ms.scheduledMessages()
+ .domainId(TestHelper.domainId)
+ .page(2)
+ .limit(10)
+ .status(ScheduledMessages.STATUS_SCHEDULED)
+ .getScheduledMessages();
+
+ assertNotNull(list);
+ assertNotNull(list.scheduledMessages);
+ assertNotNull(list.meta);
+ }
+
+
+ /**
+ * GET /v1/message-schedules/{id} returns a single scheduled message with parsed dates
+ */
+ @Test
+ public void testCanGetSingleScheduledMessage() throws MailerSendException {
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ ScheduledMessage message = ms.scheduledMessages().getScheduledMessage("test-schedule-id-123");
+
+ assertNotNull(message);
+ assertNotNull(message.id);
+ assertFalse(message.id.isEmpty(), "id should not be empty");
+ assertNotNull(message.sendAt);
+ }
+
+
+ /**
+ * DELETE /v1/message-schedules/{id} returns true on success
+ */
+ @Test
+ public void testCanDeleteScheduledMessage() throws MailerSendException {
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ boolean result = ms.scheduledMessages().deleteScheduledMessage("test-schedule-id-123");
+
+ assertTrue(result);
+ }
+
+
+ /**
+ * GET /v1/message-schedules/{id} with invalid ID returns 404
+ */
+ @Test
+ public void testGetScheduledMessageWithInvalidIdFails() {
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.scheduledMessages().getScheduledMessage("invalid-schedule-id");
+ });
+ assertEquals(404, e.code);
+ }
+
+
+ /**
+ * DELETE /v1/message-schedules/{id} with invalid ID returns 404
+ */
+ @Test
+ public void testDeleteScheduledMessageWithInvalidIdFails() {
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.scheduledMessages().deleteScheduledMessage("invalid-schedule-id");
+ });
+ assertEquals(404, e.code);
+ }
+
+
+ /**
+ * GET /v1/message-schedules with an invalid token returns 401
+ */
+ @Test
+ public void testInvalidTokenFailsWith401OnGetScheduledMessages() {
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.invalidToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.scheduledMessages().getScheduledMessages();
+ });
+ assertEquals(401, e.code);
+ }
+
+
+}
diff --git a/src/test/java/com/mailersend/sdk/tests/SenderIdentitiesTest.java b/src/test/java/com/mailersend/sdk/tests/SenderIdentitiesTest.java
new file mode 100644
index 0000000..a12410c
--- /dev/null
+++ b/src/test/java/com/mailersend/sdk/tests/SenderIdentitiesTest.java
@@ -0,0 +1,354 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.tests;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+
+import com.mailersend.sdk.MailerSend;
+import com.mailersend.sdk.exceptions.MailerSendException;
+import com.mailersend.sdk.senderidentities.SenderIdentitiesList;
+import com.mailersend.sdk.senderidentities.SenderIdentity;
+import com.mailersend.sdk.vcr.VcrRecorder;
+
+public class SenderIdentitiesTest {
+
+ private static final String IDENTITY_ID = "ident-id-123";
+ private static final String IDENTITY_EMAIL = "test@example.com";
+
+ @BeforeEach
+ public void setupEach(TestInfo info) throws IOException {
+ VcrRecorder.useRecording("SenderIdentitiesTest_" + info.getDisplayName());
+ }
+
+ @AfterEach
+ public void afterEach() throws IOException {
+ VcrRecorder.stopRecording();
+ }
+
+
+ /**
+ * Test retrieving a list of sender identities - behavior: GET /identities
+ */
+ @Test
+ public void testGetIdentities() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SenderIdentitiesList list = ms.senderIdentities().getIdentities();
+
+ assertNotNull(list);
+ assertNotNull(list.identities);
+ assertTrue(list.identities.length > 0);
+ assertNotNull(list.identities[0].id);
+ assertNotNull(list.identities[0].email);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test retrieving a single sender identity by ID - behavior: GET /identities/{id}
+ */
+ @Test
+ public void testGetIdentity() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SenderIdentity identity = ms.senderIdentities().getIdentity(IDENTITY_ID);
+
+ assertNotNull(identity);
+ assertEquals(IDENTITY_ID, identity.id);
+ assertEquals(IDENTITY_EMAIL, identity.email);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test retrieving a sender identity by email - behavior: GET /identities/email/{email}
+ */
+ @Test
+ public void testGetIdentityByEmail() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SenderIdentity identity = ms.senderIdentities().getIdentityByEmail(IDENTITY_EMAIL);
+
+ assertNotNull(identity);
+ assertEquals(IDENTITY_EMAIL, identity.email);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test creating a sender identity - behavior: POST /identities with all fields
+ */
+ @Test
+ public void testCreateIdentity() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SenderIdentity identity = ms.senderIdentities().builder()
+ .domainId(TestHelper.domainId)
+ .email(IDENTITY_EMAIL)
+ .name("Test Identity")
+ .createIdentity();
+
+ assertNotNull(identity);
+ assertNotNull(identity.id);
+ assertEquals(IDENTITY_EMAIL, identity.email);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test that creating an identity without domain ID throws an exception - validation
+ */
+ @Test
+ public void testCreateIdentityWithoutDomainId() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.senderIdentities().builder()
+ .email(IDENTITY_EMAIL)
+ .name("Test Identity")
+ .createIdentity();
+ });
+
+ assertEquals("Domain ID cannot be empty", ex.getMessage());
+ }
+
+
+ /**
+ * Test that creating an identity without email throws an exception - validation
+ */
+ @Test
+ public void testCreateIdentityWithoutEmail() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.senderIdentities().builder()
+ .domainId(TestHelper.domainId)
+ .name("Test Identity")
+ .createIdentity();
+ });
+
+ assertEquals("Email cannot be empty", ex.getMessage());
+ }
+
+
+ /**
+ * Test updating a sender identity by ID - behavior: PUT /identities/{id}
+ * Only name, reply_to_email, reply_to_name should be sent
+ */
+ @Test
+ public void testUpdateIdentity() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SenderIdentity identity = ms.senderIdentities().builder()
+ .name("Updated Identity")
+ .replyToEmail("reply@example.com")
+ .replyToName("Reply Name")
+ .updateIdentity(IDENTITY_ID);
+
+ assertNotNull(identity);
+ assertEquals("Updated Identity", identity.name);
+ assertEquals("reply@example.com", identity.replyToEmail);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test updating a sender identity by email - behavior: PUT /identities/email/{email}
+ */
+ @Test
+ public void testUpdateIdentityByEmail() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SenderIdentity identity = ms.senderIdentities().builder()
+ .name("Updated Identity")
+ .replyToEmail("reply@example.com")
+ .replyToName("Reply Name")
+ .updateIdentityByEmail(IDENTITY_EMAIL);
+
+ assertNotNull(identity);
+ assertEquals("Updated Identity", identity.name);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test that updating an identity with a blank ID throws an exception - validation
+ */
+ @Test
+ public void testUpdateIdentityWithoutId() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.senderIdentities().builder()
+ .name("Updated Identity")
+ .updateIdentity(" ");
+ });
+
+ assertEquals("Identity ID cannot be empty", ex.getMessage());
+ }
+
+
+ /**
+ * Test that updating an identity by email with a blank email throws an exception - validation
+ */
+ @Test
+ public void testUpdateIdentityByEmailWithoutEmail() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.senderIdentities().builder()
+ .name("Updated Identity")
+ .updateIdentityByEmail(" ");
+ });
+
+ assertEquals("Email cannot be empty", ex.getMessage());
+ }
+
+
+ /**
+ * Test deleting a sender identity by ID - behavior: DELETE /identities/{id} returns true
+ */
+ @Test
+ public void testDeleteIdentity() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ boolean result = ms.senderIdentities().deleteIdentity(IDENTITY_ID);
+
+ assertTrue(result);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test deleting a sender identity by email - behavior: DELETE /identities/email/{email} returns true
+ */
+ @Test
+ public void testDeleteIdentityByEmail() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ boolean result = ms.senderIdentities().deleteIdentityByEmail(IDENTITY_EMAIL);
+
+ assertTrue(result);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test resending confirmation for a sender identity - behavior: POST /identities/{id}/resend
+ */
+ @Test
+ public void testResendConfirmation() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SenderIdentity identity = ms.senderIdentities().resendConfirmation(IDENTITY_ID);
+
+ assertNotNull(identity);
+ assertEquals(IDENTITY_ID, identity.id);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+}
diff --git a/src/test/java/com/mailersend/sdk/tests/SmsActivitiesTest.java b/src/test/java/com/mailersend/sdk/tests/SmsActivitiesTest.java
new file mode 100644
index 0000000..5835c57
--- /dev/null
+++ b/src/test/java/com/mailersend/sdk/tests/SmsActivitiesTest.java
@@ -0,0 +1,132 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.tests;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+
+import com.mailersend.sdk.MailerSend;
+import com.mailersend.sdk.exceptions.MailerSendException;
+import com.mailersend.sdk.sms.activities.SmsActivityList;
+import com.mailersend.sdk.sms.activities.SmsMessageActivity;
+import com.mailersend.sdk.vcr.VcrRecorder;
+
+public class SmsActivitiesTest {
+
+ @BeforeEach
+ public void setupEach(TestInfo info) throws IOException
+ {
+ VcrRecorder.useRecording("SmsActivitiesTest_" + info.getDisplayName());
+ }
+
+ @AfterEach
+ public void afterEach() throws IOException
+ {
+ VcrRecorder.stopRecording();
+ }
+
+ /**
+ * Tests that a list of SMS activities can be retrieved
+ */
+ @Test
+ public void testGetSmsActivities() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SmsActivityList list = ms.sms().activities().getActivities();
+
+ assertNotNull(list.smsActivities);
+ assertEquals("sent", list.smsActivities[0].status);
+
+ } catch (MailerSendException e) {
+
+ fail();
+ }
+ }
+
+ /**
+ * Tests that SMS activity for a specific message can be retrieved
+ */
+ @Test
+ public void testGetSmsMessageActivity() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SmsMessageActivity activity = ms.sms().activities().getMessageActivity("sms-msg-id-test-1");
+
+ assertNotNull(activity);
+ assertEquals("sms-msg-id-test-1", activity.id);
+ assertNotNull(activity.smsActivity);
+
+ } catch (MailerSendException e) {
+
+ fail();
+ }
+ }
+
+ /**
+ * Tests that the status filter is included in the request URL when set
+ */
+ @Test
+ public void testGetActivitiesWithStatusFilter() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SmsActivityList list = ms.sms().activities()
+ .addStatusFilter("sent")
+ .getActivities();
+
+ assertNotNull(list.smsActivities);
+ assertEquals("sent", list.smsActivities[0].status);
+
+ } catch (MailerSendException e) {
+
+ fail();
+ }
+ }
+
+ /**
+ * Tests that the sms_number_id filter is included in the request URL when set
+ */
+ @Test
+ public void testGetActivitiesWithSmsNumberIdFilter() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SmsActivityList list = ms.sms().activities()
+ .smsNumberId(TestHelper.smsPhoneNumberId)
+ .getActivities();
+
+ assertNotNull(list.smsActivities);
+
+ } catch (MailerSendException e) {
+
+ fail();
+ }
+ }
+}
diff --git a/src/test/java/com/mailersend/sdk/tests/SmsInboundRoutesTests.java b/src/test/java/com/mailersend/sdk/tests/SmsInboundRoutesTests.java
index 037667a..8f7c773 100644
--- a/src/test/java/com/mailersend/sdk/tests/SmsInboundRoutesTests.java
+++ b/src/test/java/com/mailersend/sdk/tests/SmsInboundRoutesTests.java
@@ -31,7 +31,7 @@ public void afterEach() throws IOException
}
@Test
- public void TestGetSmsInboundRoutes() {
+ public void testGetSmsInboundRoutes() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -53,7 +53,7 @@ public void TestGetSmsInboundRoutes() {
}
@Test
- public void TestUpdateSmsInboundRoute() {
+ public void testUpdateSmsInboundRoute() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -80,7 +80,7 @@ public void TestUpdateSmsInboundRoute() {
@Test
- public void TestGetSingleSmsInboundRoute() {
+ public void testGetSingleSmsInboundRoute() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -100,7 +100,7 @@ public void TestGetSingleSmsInboundRoute() {
}
@Test
- public void TestAddSmsInboundRoute() {
+ public void testAddSmsInboundRoute() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -124,7 +124,7 @@ public void TestAddSmsInboundRoute() {
}
@Test
- public void TestDeleteSmsInboundRoute() {
+ public void testDeleteSmsInboundRoute() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
diff --git a/src/test/java/com/mailersend/sdk/tests/SmsMessagesTest.java b/src/test/java/com/mailersend/sdk/tests/SmsMessagesTest.java
new file mode 100644
index 0000000..21af411
--- /dev/null
+++ b/src/test/java/com/mailersend/sdk/tests/SmsMessagesTest.java
@@ -0,0 +1,84 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.tests;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+
+import com.mailersend.sdk.MailerSend;
+import com.mailersend.sdk.exceptions.MailerSendException;
+import com.mailersend.sdk.sms.messages.SmsMessage;
+import com.mailersend.sdk.sms.messages.SmsMessageList;
+import com.mailersend.sdk.vcr.VcrRecorder;
+
+public class SmsMessagesTest {
+
+ @BeforeEach
+ public void setupEach(TestInfo info) throws IOException
+ {
+ VcrRecorder.useRecording("SmsMessagesTest_" + info.getDisplayName());
+ }
+
+ @AfterEach
+ public void afterEach() throws IOException
+ {
+ VcrRecorder.stopRecording();
+ }
+
+ /**
+ * Tests that a list of SMS messages can be retrieved and contains expected data
+ */
+ @Test
+ public void testGetSmsMessages() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SmsMessageList list = ms.sms().messages().getMessages();
+
+ assertNotNull(list.messages);
+ assertEquals("sms-msg-id-test-1", list.messages[0].id);
+
+ } catch (MailerSendException e) {
+
+ fail();
+ }
+ }
+
+ /**
+ * Tests that a single SMS message can be retrieved by ID
+ */
+ @Test
+ public void testGetSingleSmsMessage() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SmsMessage message = ms.sms().messages().getMessage("sms-msg-id-test-1");
+
+ assertNotNull(message);
+ assertEquals("sms-msg-id-test-1", message.id);
+
+ } catch (MailerSendException e) {
+
+ fail();
+ }
+ }
+}
diff --git a/src/test/java/com/mailersend/sdk/tests/SmsPhoneNumbersTest.java b/src/test/java/com/mailersend/sdk/tests/SmsPhoneNumbersTest.java
index 6c7fa33..2c72399 100644
--- a/src/test/java/com/mailersend/sdk/tests/SmsPhoneNumbersTest.java
+++ b/src/test/java/com/mailersend/sdk/tests/SmsPhoneNumbersTest.java
@@ -1,6 +1,8 @@
package com.mailersend.sdk.tests;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
@@ -23,58 +25,127 @@ public void setupEach(TestInfo info) throws IOException
{
VcrRecorder.useRecording("SmsPhoneNumbersTest_" + info.getDisplayName());
}
-
+
@AfterEach
public void afterEach() throws IOException
{
VcrRecorder.stopRecording();
}
-
+
/**
* Gets a lists of phone numbers
*/
@Test
- public void TestPhoneNumbersRetrieval() {
-
+ public void testPhoneNumbersRetrieval() {
+
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
+
PhoneNumberList numbers = ms.sms().phoneNumbers().getPhoneNumbers();
-
+
for (PhoneNumber number : numbers.phoneNumbers) {
-
+
System.out.println(number.id);
}
} catch (MailerSendException e) {
-
+
fail();
}
}
-
+
/**
* Gets a single phone number
*/
@Test
- public void TestSinglePhoneNumberRetrieval() {
-
+ public void testSinglePhoneNumberRetrieval() {
+
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
+
PhoneNumberList numbers = ms.sms().phoneNumbers().getPhoneNumbers();
-
+
String phoneNumberId = numbers.phoneNumbers[0].id;
-
+
PhoneNumber number = ms.sms().phoneNumbers().getPhoneNumber(phoneNumberId);
-
+
assertEquals(phoneNumberId, number.id);
} catch (MailerSendException e) {
-
+
+ fail();
+ }
+ }
+
+ /**
+ * Tests that a phone number can be updated (paused=true) and the response reflects the change
+ */
+ @Test
+ public void testUpdatePhoneNumber() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ PhoneNumber number = ms.sms().phoneNumbers().updatePhoneNumber(
+ TestHelper.smsPhoneNumberId, true);
+
+ assertNotNull(number);
+ assertEquals(TestHelper.smsPhoneNumberId, number.id);
+ assertTrue(number.paused);
+
+ } catch (MailerSendException e) {
+
+ fail();
+ }
+ }
+
+ /**
+ * Tests that a phone number can be deleted and returns true on success
+ */
+ @Test
+ public void testDeletePhoneNumber() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ boolean result = ms.sms().phoneNumbers().deletePhoneNumber(TestHelper.smsPhoneNumberId);
+
+ assertTrue(result);
+
+ } catch (MailerSendException e) {
+
+ fail();
+ }
+ }
+
+ /**
+ * Tests that the paused filter is included in the request URL when set
+ */
+ @Test
+ public void testPhoneNumbersWithPausedFilter() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ PhoneNumberList numbers = ms.sms().phoneNumbers()
+ .paused(true)
+ .getPhoneNumbers();
+
+ assertNotNull(numbers.phoneNumbers);
+ assertTrue(numbers.phoneNumbers[0].paused);
+
+ } catch (MailerSendException e) {
+
fail();
}
}
diff --git a/src/test/java/com/mailersend/sdk/tests/SmsRecipientsTest.java b/src/test/java/com/mailersend/sdk/tests/SmsRecipientsTest.java
index 635cfa4..3378d89 100644
--- a/src/test/java/com/mailersend/sdk/tests/SmsRecipientsTest.java
+++ b/src/test/java/com/mailersend/sdk/tests/SmsRecipientsTest.java
@@ -1,6 +1,7 @@
package com.mailersend.sdk.tests;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
@@ -32,7 +33,7 @@ public void afterEach() throws IOException
@Test
- public void TestSmsRecipientsRetrieval() {
+ public void testSmsRecipientsRetrieval() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -53,7 +54,7 @@ public void TestSmsRecipientsRetrieval() {
@Test
- public void TestSmsSingleRecipientRetrieval() {
+ public void testSmsSingleRecipientRetrieval() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -72,19 +73,63 @@ public void TestSmsSingleRecipientRetrieval() {
}
@Test
- public void TestSmsRecipientUpdate() {
-
+ public void testSmsRecipientUpdate() {
+
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
+
SmsRecipientList list = ms.sms().recipients().getRecipients();
-
+
SmsRecipient recipient = ms.sms().recipients().updateRecipient(list.recipients[0].id, "opt_out");
-
+
assertEquals("opt_out", recipient.status);
-
+
+ } catch (MailerSendException ex) {
+ fail();
+ }
+ }
+
+ /**
+ * Tests that the status filter is included in the request URL when set
+ */
+ @Test
+ public void testSmsRecipientsWithStatusFilter() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SmsRecipientList list = ms.sms().recipients()
+ .status("opt_out")
+ .getRecipients();
+
+ assertEquals("opt_out", list.recipients[0].status);
+
+ } catch (MailerSendException ex) {
+ fail();
+ }
+ }
+
+ /**
+ * Tests that the sms_number_id filter is included in the request URL when set
+ */
+ @Test
+ public void testSmsRecipientsWithSmsNumberIdFilter() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SmsRecipientList list = ms.sms().recipients()
+ .numberId(TestHelper.smsPhoneNumberId)
+ .getRecipients();
+
+ assertNotNull(list.recipients);
+
} catch (MailerSendException ex) {
fail();
}
diff --git a/src/test/java/com/mailersend/sdk/tests/SmsTests.java b/src/test/java/com/mailersend/sdk/tests/SmsTests.java
index 37ddc87..1441142 100644
--- a/src/test/java/com/mailersend/sdk/tests/SmsTests.java
+++ b/src/test/java/com/mailersend/sdk/tests/SmsTests.java
@@ -31,7 +31,7 @@ public void afterEach() throws IOException
@Test
- public void TestSendSms() {
+ public void testSendSms() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
diff --git a/src/test/java/com/mailersend/sdk/tests/SmsWebhooksTests.java b/src/test/java/com/mailersend/sdk/tests/SmsWebhooksTests.java
index 166b725..aa12e52 100644
--- a/src/test/java/com/mailersend/sdk/tests/SmsWebhooksTests.java
+++ b/src/test/java/com/mailersend/sdk/tests/SmsWebhooksTests.java
@@ -33,7 +33,7 @@ public void afterEach() throws IOException
@Test
- public void TestGetSmsWebhooks() {
+ public void testGetSmsWebhooks() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -55,7 +55,7 @@ public void TestGetSmsWebhooks() {
@Test
- public void TestGetSingleSmsWebhook() {
+ public void testGetSingleSmsWebhook() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -76,7 +76,7 @@ public void TestGetSingleSmsWebhook() {
@Test
- public void TestCreateSmsWebhook() {
+ public void testCreateSmsWebhook() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -98,7 +98,7 @@ public void TestCreateSmsWebhook() {
}
@Test
- public void TestUpdateSmsWebhook() {
+ public void testUpdateSmsWebhook() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -121,7 +121,7 @@ public void TestUpdateSmsWebhook() {
@Test
- public void TestDeleteSmsWebhook() {
+ public void testDeleteSmsWebhook() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
diff --git a/src/test/java/com/mailersend/sdk/tests/SmtpUsersTest.java b/src/test/java/com/mailersend/sdk/tests/SmtpUsersTest.java
new file mode 100644
index 0000000..5c6b7ea
--- /dev/null
+++ b/src/test/java/com/mailersend/sdk/tests/SmtpUsersTest.java
@@ -0,0 +1,236 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.tests;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+
+import com.mailersend.sdk.MailerSend;
+import com.mailersend.sdk.exceptions.MailerSendException;
+import com.mailersend.sdk.smtpusers.SmtpUser;
+import com.mailersend.sdk.smtpusers.SmtpUsersList;
+import com.mailersend.sdk.vcr.VcrRecorder;
+
+public class SmtpUsersTest {
+
+ @BeforeEach
+ public void setupEach(TestInfo info) throws IOException {
+ VcrRecorder.useRecording("SmtpUsersTest_" + info.getDisplayName());
+ }
+
+ @AfterEach
+ public void afterEach() throws IOException {
+ VcrRecorder.stopRecording();
+ }
+
+ /**
+ * Tests retrieval of SMTP users list
+ */
+ @Test
+ public void testCanGetSmtpUsers() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SmtpUsersList list = ms.smtpUsers().getSmtpUsers(TestHelper.domainId);
+
+ assertNotNull(list);
+ assertNotNull(list.smtpUsers);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ /**
+ * Tests retrieval of SMTP users list with pagination parameters
+ */
+ @Test
+ public void testCanGetSmtpUsersWithPagination() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SmtpUsersList list = ms.smtpUsers()
+ .page(2)
+ .limit(10)
+ .getSmtpUsers(TestHelper.domainId);
+
+ assertNotNull(list);
+ assertNotNull(list.smtpUsers);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ /**
+ * Tests creating an SMTP user
+ */
+ @Test
+ public void testCanCreateSmtpUser() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SmtpUser smtpUser = ms.smtpUsers().smtpUserBuilder()
+ .name("Support")
+ .enabled(true)
+ .createSmtpUser(TestHelper.domainId);
+
+ assertNotNull(smtpUser);
+ assertNotNull(smtpUser.id);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ /**
+ * Tests retrieval of a single SMTP user
+ */
+ @Test
+ public void testCanGetSingleSmtpUser() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SmtpUser smtpUser = ms.smtpUsers().getSmtpUser(TestHelper.domainId, TestHelper.smtpUserId);
+
+ assertNotNull(smtpUser);
+ assertNotNull(smtpUser.id);
+ assertNotNull(smtpUser.name);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ /**
+ * Tests updating an SMTP user
+ */
+ @Test
+ public void testCanUpdateSmtpUser() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ SmtpUser smtpUser = ms.smtpUsers().smtpUserBuilder()
+ .name("Support SMTP")
+ .enabled(false)
+ .updateSmtpUser(TestHelper.domainId, TestHelper.smtpUserId);
+
+ assertNotNull(smtpUser);
+ assertNotNull(smtpUser.id);
+ assertEquals(false, smtpUser.enabled);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ /**
+ * Tests deleting an SMTP user
+ */
+ @Test
+ public void testCanDeleteSmtpUser() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ boolean deleted = ms.smtpUsers().deleteSmtpUser(TestHelper.domainId, TestHelper.smtpUserIdToDelete);
+
+ assertTrue(deleted);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ /**
+ * Tests that retrieving an SMTP user with an invalid ID throws a 404 exception
+ */
+ @Test
+ public void testGetSmtpUserWithInvalidIdFails() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.smtpUsers().getSmtpUser(TestHelper.domainId, TestHelper.invalidSmtpUserId);
+ });
+
+ assertEquals(404, e.code);
+ }
+
+ /**
+ * Tests that deleting an SMTP user with an invalid ID throws a 404 exception
+ */
+ @Test
+ public void testDeleteSmtpUserWithInvalidIdFails() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.smtpUsers().deleteSmtpUser(TestHelper.domainId, TestHelper.invalidSmtpUserId);
+ });
+
+ assertEquals(404, e.code);
+ }
+
+ /**
+ * Tests that an invalid token results in a 401 exception when listing SMTP users
+ */
+ @Test
+ public void testInvalidTokenFailsWith401OnListSmtpUsers() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.invalidToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.smtpUsers().getSmtpUsers(TestHelper.invalidTokenDomainId);
+ });
+
+ assertEquals(401, e.code);
+ }
+}
diff --git a/src/test/java/com/mailersend/sdk/tests/TemplatesTest.java b/src/test/java/com/mailersend/sdk/tests/TemplatesTest.java
index af8cdc3..feba0c0 100644
--- a/src/test/java/com/mailersend/sdk/tests/TemplatesTest.java
+++ b/src/test/java/com/mailersend/sdk/tests/TemplatesTest.java
@@ -1,13 +1,19 @@
package com.mailersend.sdk.tests;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
+import java.util.stream.Stream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.MailerSendResponse;
@@ -19,107 +25,277 @@
public class TemplatesTest {
-
@BeforeEach
public void setupEach(TestInfo info) throws IOException
{
VcrRecorder.useRecording("TemplatesTest_" + info.getDisplayName());
}
-
+
@AfterEach
public void afterEach() throws IOException
{
VcrRecorder.stopRecording();
}
-
+
/**
* Tests retrieving a list of templates
*/
@Test
- public void TestGetTemplates() {
-
+ public void testGetTemplates() {
+
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
+
TemplatesList list = ms.templates().getTemplates();
-
+
for (TemplateItem item : list.templates) {
-
+
System.out.println(item.id);
System.out.println(item.name);
}
-
+
} catch (MailerSendException e) {
e.printStackTrace();
fail();
}
-
-
+
+
}
-
-
+
+
/**
* Tests the retrieval of a single template
*/
@Test
- public void TestGetSingleTemplate() {
-
+ public void testGetSingleTemplate() {
+
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
+
TemplatesList list = ms.templates().getTemplates();
-
+
if (list.templates.length == 0) {
-
+
fail();
}
-
+
Template template = ms.templates().getTemplate(list.templates[0].id);
-
+
System.out.println(template.id);
System.out.println(template.name);
System.out.println(template.imagePath);
-
+
} catch (MailerSendException e) {
e.printStackTrace();
fail();
- }
+ }
}
-
-
+
+
/**
* Tests deleting a template
*/
@Test
- public void TestDeleteTemplate() {
-
+ public void testDeleteTemplate() {
+
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
+
TemplatesList list = ms.templates().getTemplates();
-
+
if (list.templates.length == 0) {
-
+
fail();
}
-
+
MailerSendResponse response = ms.templates().deleteTemplate(list.templates[0].id);
-
+
System.out.println(response.responseStatusCode);
-
+
} catch (MailerSendException e) {
e.printStackTrace();
fail();
- }
+ }
+ }
+
+
+ /**
+ * Tests that createTemplate() throws when html is not set
+ */
+ @Test
+ public void testCreateTemplateWithoutHtml() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.templates().builder()
+ .name("My Template")
+ .createTemplate();
+ });
+
+ assertEquals("Template html cannot be empty", e.getMessage());
+ }
+
+
+ /**
+ * Tests that createTemplate() throws when text is not set (but html is set)
+ */
+ @Test
+ public void testCreateTemplateWithoutText() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.templates().builder()
+ .name("My Template")
+ .html("Hello
")
+ .createTemplate();
+ });
+
+ assertEquals("Template text cannot be empty", e.getMessage());
+ }
+
+
+ /**
+ * Tests that name() throws when name exceeds 50 characters
+ */
+ @Test
+ public void testTemplateNameTooLong() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.templates().builder().name("a".repeat(51));
+ });
+
+ assertEquals("Template name cannot be longer than 50 characters", e.getMessage());
+ }
+
+
+ /**
+ * Tests that tags() throws when more than 5 tags are provided
+ */
+ @Test
+ public void testTemplateTooManyTags() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.templates().builder().tags(new String[]{"a", "b", "c", "d", "e", "f"});
+ });
+
+ assertEquals("Template tags cannot have more than 5 items", e.getMessage());
+ }
+
+
+ /**
+ * Tests that tags() throws when a tag exceeds 191 characters
+ */
+ @Test
+ public void testTemplateTagTooLong() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.templates().builder().tags(new String[]{"a".repeat(192)});
+ });
+
+ assertEquals("Each template tag cannot be longer than 191 characters", e.getMessage());
}
-
+
+
+ /**
+ * Tests that limit() and page() reject invalid values (parameterized)
+ */
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("invalidPaginationParams")
+ public void testGetTemplatesInvalidPagination(String label, int limit, int page, String expectedMessage) {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ if (label.contains("limit")) {
+ ms.templates().limit(limit);
+ } else {
+ ms.templates().page(page);
+ }
+ });
+
+ assertEquals(expectedMessage, e.getMessage());
+ }
+
+ static Stream invalidPaginationParams() {
+ return Stream.of(
+ Arguments.of("limit too low", 5, 1, "Limit must be between 10 and 100"),
+ Arguments.of("limit too high", 101, 1, "Limit must be between 10 and 100"),
+ Arguments.of("page too low", 10, 0, "Page must be at least 1")
+ );
+ }
+
+
+ /**
+ * Tests that getTemplate() throws when templateId is empty
+ */
+ @Test
+ public void testGetTemplateWithEmptyId() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.templates().getTemplate("");
+ });
+
+ assertEquals("Template ID cannot be empty", e.getMessage());
+ }
+
+
+ /**
+ * Tests that updateTemplate() throws when templateId is empty
+ */
+ @Test
+ public void testUpdateTemplateWithEmptyId() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.templates().builder().updateTemplate("");
+ });
+
+ assertEquals("Template ID cannot be empty", e.getMessage());
+ }
+
+
+ /**
+ * Tests that deleteTemplate() throws when templateId is empty
+ */
+ @Test
+ public void testDeleteTemplateWithEmptyId() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.templates().deleteTemplate("");
+ });
+
+ assertEquals("Template ID cannot be empty", e.getMessage());
+ }
+
}
diff --git a/src/test/java/com/mailersend/sdk/tests/TestHelper.java b/src/test/java/com/mailersend/sdk/tests/TestHelper.java
index ac76ccb..1bca582 100644
--- a/src/test/java/com/mailersend/sdk/tests/TestHelper.java
+++ b/src/test/java/com/mailersend/sdk/tests/TestHelper.java
@@ -48,10 +48,18 @@ public class TestHelper {
public static final String smsPhoneNumberId = "3yxj6lj9x14do2rm";
+ public static final String smtpUserId = "0wkg2zj19ovx5py7";
+ public static final String smtpUserIdToDelete = "0wkg2zj19ovx5py7";
+ public static final String invalidSmtpUserId = "invalid-smtp-user-id";
+ public static final String invalidTokenDomainId = "invalid-domain-id";
+
public static final String dmarcMonitorId = "dmarc-monitor-id-test";
public static final String dmarcMonitorIp = "1.2.3.4";
public static final String dmarcDomainId = "jpzkmgq7e5vl059v";
public static final String dmarcWantedRecord = "v=DMARC1; p=reject; rua=mailto:dmarc@example.com;";
+
+ public static final String blocklistMonitorId = "blocklist-monitor-id-test";
+ public static final String blocklistMonitorAddress = "test-domain.com";
/**
* Creates a basic email with the above configuration
diff --git a/src/test/java/com/mailersend/sdk/tests/TokensTest.java b/src/test/java/com/mailersend/sdk/tests/TokensTest.java
index 03a69e1..0916902 100644
--- a/src/test/java/com/mailersend/sdk/tests/TokensTest.java
+++ b/src/test/java/com/mailersend/sdk/tests/TokensTest.java
@@ -7,6 +7,10 @@
**************************************************/
package com.mailersend.sdk.tests;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
@@ -21,6 +25,7 @@
import com.mailersend.sdk.exceptions.MailerSendException;
import com.mailersend.sdk.tokens.Token;
import com.mailersend.sdk.tokens.TokenAdd;
+import com.mailersend.sdk.tokens.TokenListResponse;
import com.mailersend.sdk.tokens.TokenScopes;
import com.mailersend.sdk.vcr.VcrRecorder;
@@ -43,7 +48,7 @@ public void afterEach() throws IOException
* Test token creation
*/
@Test
- public void TestCreateToken() {
+ public void testCreateToken() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -72,7 +77,7 @@ public void TestCreateToken() {
* Test token update (pause)
*/
@Test
- public void UpdateToken() {
+ public void updateToken() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
@@ -95,21 +100,218 @@ public void UpdateToken() {
* Test token deletion
*/
@Test
- public void DeleteToken() {
-
+ public void deleteToken() {
+
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
MailerSendResponse response = ms.tokens().deleteToken(TestHelper.tokenIdToDelete);
-
+
System.out.println(response.responseStatusCode);
-
+
} catch (MailerSendException e) {
-
+
e.printStackTrace();
fail();
}
}
-
+
+
+ /**
+ * Test retrieving a list of tokens - behavior: GET /token returns list
+ */
+ @Test
+ public void testGetTokens() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ TokenListResponse response = ms.tokens().getTokens();
+
+ assertNotNull(response);
+ assertNotNull(response.tokens);
+ assertTrue(response.tokens.length > 0);
+ assertNotNull(response.tokens[0].id);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test retrieving a single token - behavior: GET /token/{id} returns token with scopes
+ */
+ @Test
+ public void testGetToken() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ Token token = ms.tokens().getToken(TestHelper.tokenIdToPause);
+
+ assertNotNull(token);
+ assertNotNull(token.id);
+ assertNotNull(token.scopes);
+ assertTrue(token.scopes.length > 0);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test updating token name and status - behavior: PUT /token/{id}
+ */
+ @Test
+ public void testUpdateTokenNameAndStatus() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ Token token = ms.tokens().updateToken(TestHelper.tokenIdToPause, "Updated Name", "pause");
+
+ assertNotNull(token);
+ assertEquals("Updated Name", token.name);
+ assertEquals("pause", token.status);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test that updating token without name or status throws an exception
+ */
+ @Test
+ public void testUpdateTokenWithoutNameOrStatus() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.tokens().updateToken(TestHelper.tokenIdToPause, null, null);
+ });
+
+ assertEquals("At least one of name or status must be provided", ex.getMessage());
+ }
+
+
+ /**
+ * Test that creating a token with a null name throws an exception
+ */
+ @Test
+ public void testCreateTokenWithNullName() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.tokens().addBuilder()
+ .domainId(TestHelper.domainId)
+ .addScope(TokenScopes.emailFull)
+ .addToken();
+ });
+
+ assertEquals("Token name cannot be null or empty", ex.getMessage());
+ }
+
+
+ /**
+ * Test that creating a token with an empty name throws an exception
+ */
+ @Test
+ public void testCreateTokenWithEmptyName() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.tokens().addBuilder()
+ .name(" ")
+ .domainId(TestHelper.domainId)
+ .addScope(TokenScopes.emailFull)
+ .addToken();
+ });
+
+ assertEquals("Token name cannot be null or empty", ex.getMessage());
+ }
+
+
+ /**
+ * Test that creating a token with a name longer than 50 chars throws an exception
+ */
+ @Test
+ public void testCreateTokenWithLongName() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.tokens().addBuilder()
+ .name("A".repeat(51))
+ .domainId(TestHelper.domainId)
+ .addScope(TokenScopes.emailFull)
+ .addToken();
+ });
+
+ assertEquals("Token name cannot be longer than 50 characters", ex.getMessage());
+ }
+
+
+ /**
+ * Test that creating a token with no scopes throws an exception
+ */
+ @Test
+ public void testCreateTokenWithNoScopes() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.tokens().addBuilder()
+ .name("Valid Name")
+ .domainId(TestHelper.domainId)
+ .addToken();
+ });
+
+ assertEquals("At least one scope is required", ex.getMessage());
+ }
+
+
+ /**
+ * Test that adding an invalid scope throws an exception
+ */
+ @Test
+ public void testCreateTokenWithInvalidScope() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.tokens().addBuilder()
+ .name("Valid Name")
+ .domainId(TestHelper.domainId)
+ .addScope("invalid_scope_value")
+ .addToken();
+ });
+
+ assertEquals("Scope is not valid", ex.getMessage());
+ }
+
}
diff --git a/src/test/java/com/mailersend/sdk/tests/UsersTest.java b/src/test/java/com/mailersend/sdk/tests/UsersTest.java
new file mode 100644
index 0000000..d63569b
--- /dev/null
+++ b/src/test/java/com/mailersend/sdk/tests/UsersTest.java
@@ -0,0 +1,369 @@
+/*************************************************
+ * MailerSend Java SDK
+ * https://github.com/mailersend/mailersend-java
+ *
+ * @author MailerSend
+ * https://mailersend.com
+ **************************************************/
+package com.mailersend.sdk.tests;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+
+import com.mailersend.sdk.MailerSend;
+import com.mailersend.sdk.exceptions.MailerSendException;
+import com.mailersend.sdk.users.Invite;
+import com.mailersend.sdk.users.InvitesList;
+import com.mailersend.sdk.users.User;
+import com.mailersend.sdk.users.UsersList;
+import com.mailersend.sdk.vcr.VcrRecorder;
+
+public class UsersTest {
+
+ private static final String USER_ID = "user-id-123";
+ private static final String INVITE_ID = "invite-id-123";
+ private static final String USER_EMAIL = "newuser@example.com";
+
+ @BeforeEach
+ public void setupEach(TestInfo info) throws IOException {
+ VcrRecorder.useRecording("UsersTest_" + info.getDisplayName());
+ }
+
+ @AfterEach
+ public void afterEach() throws IOException {
+ VcrRecorder.stopRecording();
+ }
+
+
+ /**
+ * Test retrieving a list of users - behavior: GET /users
+ */
+ @Test
+ public void testGetUsers() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ UsersList list = ms.users().getUsers();
+
+ assertNotNull(list);
+ assertNotNull(list.users);
+ assertTrue(list.users.length > 0);
+ assertNotNull(list.users[0].id);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test retrieving a single user by ID - behavior: GET /users/{id}
+ */
+ @Test
+ public void testGetUser() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ User user = ms.users().getUser(USER_ID);
+
+ assertNotNull(user);
+ assertEquals(USER_ID, user.id);
+ assertNotNull(user.email);
+ assertNotNull(user.role);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test inviting a user - behavior: POST /users with all fields
+ */
+ @Test
+ public void testInviteUser() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ Invite invite = ms.users().builder()
+ .email(USER_EMAIL)
+ .role("Admin")
+ .inviteUser();
+
+ assertNotNull(invite);
+ assertNotNull(invite.id);
+ assertEquals(USER_EMAIL, invite.email);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test that inviting a user without email throws an exception - validation
+ */
+ @Test
+ public void testInviteUserWithoutEmail() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.users().builder()
+ .role("Admin")
+ .inviteUser();
+ });
+
+ assertEquals("User email cannot be null or empty", ex.getMessage());
+ }
+
+
+ /**
+ * Test that inviting a user without a role throws an exception - validation
+ */
+ @Test
+ public void testInviteUserWithoutRole() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.users().builder()
+ .email(USER_EMAIL)
+ .inviteUser();
+ });
+
+ assertEquals("User role cannot be null or empty", ex.getMessage());
+ }
+
+
+ /**
+ * Test that inviting a Custom User without permissions throws an exception - validation
+ */
+ @Test
+ public void testInviteCustomUserWithoutPermissions() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.users().builder()
+ .email(USER_EMAIL)
+ .role("Custom User")
+ .inviteUser();
+ });
+
+ assertEquals("Permissions are required for Custom User role", ex.getMessage());
+ }
+
+
+ /**
+ * Test updating a user - behavior: PUT /users/{id}
+ */
+ @Test
+ public void testUpdateUser() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ User user = ms.users().builder()
+ .role("Manager")
+ .updateUser(USER_ID);
+
+ assertNotNull(user);
+ assertEquals(USER_ID, user.id);
+ assertEquals("Manager", user.role);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test that updating a user without an ID throws an exception - validation
+ */
+ @Test
+ public void testUpdateUserWithoutId() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.users().builder()
+ .role("Manager")
+ .updateUser(null);
+ });
+
+ assertEquals("User ID cannot be null or empty", ex.getMessage());
+ }
+
+
+ /**
+ * Test that updating a Custom User without permissions throws an exception - validation
+ */
+ @Test
+ public void testUpdateCustomUserWithoutPermissions() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException ex = assertThrows(MailerSendException.class, () -> {
+ ms.users().builder()
+ .role("Custom User")
+ .updateUser(USER_ID);
+ });
+
+ assertEquals("Permissions are required for Custom User role", ex.getMessage());
+ }
+
+
+ /**
+ * Test deleting a user - behavior: DELETE /users/{id} returns true
+ */
+ @Test
+ public void testDeleteUser() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ boolean result = ms.users().deleteUser(USER_ID);
+
+ assertTrue(result);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test retrieving a list of invites - behavior: GET /invites
+ */
+ @Test
+ public void testGetInvites() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ InvitesList list = ms.users().getInvites();
+
+ assertNotNull(list);
+ assertNotNull(list.invites);
+ assertTrue(list.invites.length > 0);
+ assertNotNull(list.invites[0].id);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test retrieving a single invite by ID - behavior: GET /invites/{id}
+ */
+ @Test
+ public void testGetInvite() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ Invite invite = ms.users().getInvite(INVITE_ID);
+
+ assertNotNull(invite);
+ assertEquals(INVITE_ID, invite.id);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test resending an invite - behavior: POST /invites/{id}/resend
+ */
+ @Test
+ public void testResendInvite() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ Invite invite = ms.users().resendInvite(INVITE_ID);
+
+ assertNotNull(invite);
+ assertEquals(INVITE_ID, invite.id);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+
+ /**
+ * Test cancelling (deleting) an invite - behavior: DELETE /invites/{id} returns true
+ */
+ @Test
+ public void testDeleteInvite() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ try {
+
+ boolean result = ms.users().deleteInvite(INVITE_ID);
+
+ assertTrue(result);
+
+ } catch (MailerSendException e) {
+
+ e.printStackTrace();
+ fail();
+ }
+ }
+}
diff --git a/src/test/java/com/mailersend/sdk/tests/WebhooksTest.java b/src/test/java/com/mailersend/sdk/tests/WebhooksTest.java
index 9eb3565..0c2a550 100644
--- a/src/test/java/com/mailersend/sdk/tests/WebhooksTest.java
+++ b/src/test/java/com/mailersend/sdk/tests/WebhooksTest.java
@@ -1,18 +1,23 @@
/*************************************************
* MailerSend Java SDK
* https://github.com/mailersend/mailersend-java
- *
+ *
* @author MailerSend
* https://mailersend.com
**************************************************/
package com.mailersend.sdk.tests;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.MailerSendResponse;
@@ -23,6 +28,7 @@
import com.mailersend.sdk.webhooks.WebhooksList;
import java.io.IOException;
+import java.util.stream.Stream;
import java.util.concurrent.ThreadLocalRandom;
public class WebhooksTest {
@@ -32,158 +38,324 @@ public void setupEach(TestInfo info) throws IOException
{
VcrRecorder.useRecording("WebhooksTest_" + info.getDisplayName());
}
-
+
@AfterEach
public void afterEach() throws IOException
{
VcrRecorder.stopRecording();
}
-
+
/**
* Tests the creation of a webhook
*/
@Test
- public void TestWebhookCreation() {
+ public void testWebhookCreation() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
+
String webhookTestUrl = "https://example.com/test-webhook-creation-123";
-
+
Webhook webhook = ms.webhooks().builder()
.name("Test webook")
.url(webhookTestUrl)
.addEvent(WebhookEvents.ACTIVITY_OPENED)
.addEvent(WebhookEvents.ACTIVITY_CLICKED)
.createWebhook(TestHelper.domainId);
-
+
System.out.println(webhook.name);
} catch (MailerSendException e) {
-
+
e.printStackTrace();
fail();
}
}
-
-
+
+
/**
* Tests updating a webhook
*/
@Test
- public void TestUpdateWebhook() {
+ public void testUpdateWebhook() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
+
WebhooksList list = ms.webhooks().getWebhooks(TestHelper.domainId);
-
+
if (list.webhooks.length == 0) {
-
+
fail();
}
-
+
Webhook webhook = ms.webhooks()
.builder()
.name("Updated webhook name 2")
.updateWebhook(list.webhooks[0].id);
-
+
System.out.println(webhook.name);
} catch (MailerSendException e) {
-
+
e.printStackTrace();
fail();
}
}
-
-
+
+
/**
* Tests deleting a webhook
*/
@Test
- public void TestDeleteWebhook() {
+ public void testDeleteWebhook() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
+
WebhooksList list = ms.webhooks().getWebhooks(TestHelper.domainId);
-
+
if (list.webhooks.length == 0) {
-
+
fail();
}
-
+
boolean response = ms.webhooks().deleteWebhook(list.webhooks[0].id);
-
+
System.out.println(response);
} catch (MailerSendException e) {
-
+
e.printStackTrace();
fail();
}
}
-
-
+
+
/**
* Tests retrieving a single webhook
*/
@Test
- public void TestGetWebhook() {
+ public void testGetWebhook() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
+
WebhooksList list = ms.webhooks().getWebhooks(TestHelper.domainId);
-
+
if (list.webhooks.length == 0) {
-
+
fail();
}
-
+
Webhook webhook = ms.webhooks().getWebhook(list.webhooks[0].id);
-
+
System.out.println(webhook.name);
} catch (MailerSendException e) {
-
+
e.printStackTrace();
fail();
}
}
-
-
+
+
/**
* Tests the retrieval of the webhooks
*/
@Test
- public void TestWebhooksList() {
+ public void testWebhooksList() {
MailerSend ms = new MailerSend();
ms.setToken(TestHelper.validToken);
-
+
try {
-
+
WebhooksList list = ms.webhooks().getWebhooks(TestHelper.domainId);
-
+
for (Webhook webhook : list.webhooks) {
-
+
System.out.println(webhook.name);
}
} catch (MailerSendException e) {
-
+
e.printStackTrace();
fail();
}
}
+
+
+ /**
+ * Tests that createWebhook() throws when name is not set
+ */
+ @Test
+ public void testCreateWebhookWithEmptyName() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.webhooks().builder()
+ .url("https://example.com/webhook")
+ .addEvent(WebhookEvents.ACTIVITY_OPENED)
+ .createWebhook(TestHelper.domainId);
+ });
+
+ assertEquals("Webhook name cannot be empty", e.getMessage());
+ }
+
+
+ /**
+ * Tests that createWebhook() throws when url is not set
+ */
+ @Test
+ public void testCreateWebhookWithEmptyUrl() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.webhooks().builder()
+ .name("My Webhook")
+ .addEvent(WebhookEvents.ACTIVITY_OPENED)
+ .createWebhook(TestHelper.domainId);
+ });
+
+ assertEquals("Webhook URL cannot be empty", e.getMessage());
+ }
+
+
+ /**
+ * Tests that createWebhook() throws when domainId is empty
+ */
+ @Test
+ public void testCreateWebhookWithEmptyDomainId() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.webhooks().builder()
+ .name("My Webhook")
+ .url("https://example.com/webhook")
+ .addEvent(WebhookEvents.ACTIVITY_OPENED)
+ .createWebhook("");
+ });
+
+ assertEquals("Domain ID cannot be empty", e.getMessage());
+ }
+
+
+ /**
+ * Tests that createWebhook() throws when an invalid event is added
+ */
+ @Test
+ public void testCreateWebhookWithInvalidEvent() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.webhooks().builder()
+ .name("My Webhook")
+ .url("https://example.com/webhook")
+ .addEvent("invalid.event")
+ .createWebhook(TestHelper.domainId);
+ });
+
+ assertEquals("Webhook event is not valid", e.getMessage());
+ }
+
+
+ /**
+ * Tests that createWebhook() throws when no events are set
+ */
+ @Test
+ public void testCreateWebhookWithNoEvents() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.webhooks().builder()
+ .name("My Webhook")
+ .url("https://example.com/webhook")
+ .createWebhook(TestHelper.domainId);
+ });
+
+ assertEquals("At least one webhook event is required", e.getMessage());
+ }
+
+
+ /**
+ * Tests that getWebhooks() throws when domainId is empty
+ */
+ @Test
+ public void testGetWebhooksWithEmptyDomainId() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.webhooks().getWebhooks("");
+ });
+
+ assertEquals("Domain ID cannot be empty", e.getMessage());
+ }
+
+
+ /**
+ * Tests that limit() and page() reject invalid values (parameterized)
+ */
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("invalidPaginationParams")
+ public void testGetWebhooksInvalidPagination(String label, int limit, int page, String expectedMessage) {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ if (label.contains("limit")) {
+ ms.webhooks().limit(limit);
+ } else {
+ ms.webhooks().page(page);
+ }
+ });
+
+ assertEquals(expectedMessage, e.getMessage());
+ }
+
+ static Stream invalidPaginationParams() {
+ return Stream.of(
+ Arguments.of("limit too low", 5, 1, "Limit must be between 10 and 100"),
+ Arguments.of("limit too high", 101, 1, "Limit must be between 10 and 100"),
+ Arguments.of("page too low", 10, 0, "Page must be at least 1")
+ );
+ }
+
+
+ /**
+ * Tests that version() throws when version is not 1 or 2
+ */
+ @Test
+ public void testWebhookVersionInvalid() {
+
+ MailerSend ms = new MailerSend();
+ ms.setToken(TestHelper.validToken);
+
+ MailerSendException e = assertThrows(MailerSendException.class, () -> {
+ ms.webhooks().builder().version(3);
+ });
+
+ assertEquals("Webhook version must be 1 or 2", e.getMessage());
+ }
}
diff --git a/src/test/resources/fixtures/ActivitiesTest_TestActivitiesFilterByEvent().json b/src/test/resources/fixtures/ActivitiesTest_TestActivitiesFilterByEvent().json
index fe4459e..dccfc44 100644
--- a/src/test/resources/fixtures/ActivitiesTest_TestActivitiesFilterByEvent().json
+++ b/src/test/resources/fixtures/ActivitiesTest_TestActivitiesFilterByEvent().json
@@ -1 +1 @@
-{"5fb305500fe7babdf50fb580707a56dd0a583fe6":{"body":"{\"data\":[{\"id\":\"62ff8b75b1ffd57ddb0b5eeb\",\"created_at\":\"2022-08-19T13:09:09.604000Z\",\"updated_at\":\"2022-08-19T13:09:09.604000Z\",\"type\":\"opened\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}}]}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d32e8c88116f53-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:19:36 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["57"]},"statusCode":200}}
\ No newline at end of file
+{"5fb305500fe7babdf50fb580707a56dd0a583fe6":{"body":"{\"data\":[{\"id\":\"62ff8b75b1ffd57ddb0b5eeb\",\"created_at\":\"2022-08-19T13:09:09.604000Z\",\"updated_at\":\"2022-08-19T13:09:09.604000Z\",\"type\":\"opened\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}}]}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d32e8c88116f53-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:19:36 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["57"]},"statusCode":200},"21cdb7eb6d9e5bdd34900e4af70da24cb3c5f22b":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89ab538a04692f-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 15:59:01 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["35"]},"statusCode":401},"5ac534d8004ec3dec0ad8353e9d88c4afbc15d23":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa04ce27943f369-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 09:54:05 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["38"]},"statusCode":401},"b3ee440a6821f5b07eb6d02caa7dc75a4bbb5445":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89d8bbdc6c547f-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 16:30:01 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["32"]},"statusCode":401},"dbfed4421d7eeab993cc907f90925d61f222a2c4":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9f80850f738c92-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 07:34:35 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["25"]},"statusCode":401},"3a6fa23733479e811fde14e1b7c363d8efc25b29":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4fc18d16914-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:05 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["25"]},"statusCode":401},"4abbfc6ddd2af93f9b8395c86af03fbdf8eee8ea":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa0abea3b78e3b0-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:58:58 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["25"]},"statusCode":401},"e2391612f81f7c1caaf2fb8125677220d4de11af":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9f812abe28547f-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 07:35:01 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["38"]},"statusCode":401},"3c2796bed7c503aed37168da030f12a04bb89342":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa065b5ad5248a0-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:11:02 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["34"]},"statusCode":401},"07419839364c01f09746ef6864630ed5a95a900c":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9fad836f9a7859-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:05:18 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["26"]},"statusCode":401},"a8b06e1afee451416134d8e8c8b729a5ea8e6d18":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9fadce58661df8-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:05:30 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["32"]},"statusCode":401},"a8988e38507461be5c53bc919a3de04335d109fb":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa06c2e79b462e8-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:15:27 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["24"]},"statusCode":401},"6c29d7434e7523ea7ff29f65834c32bc48b1f466":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa06b1149415910-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:14:42 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["25"]},"statusCode":401},"f318a9417e89be09f86b6252d8d9d4e0a4af7035":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa06b73cd4a5910-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:14:57 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["33"]},"statusCode":401},"02fe6e9ffece5d3c0d2759901908c45de18ee795":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9f7ce30e704813-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 07:32:06 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["24"]},"statusCode":401},"f690402d5d31915226fd0d28a85154013c593a13":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa08be95f3a547f-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:37:07 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["33"]},"statusCode":401},"552f07b70502c37538625a03601e6f0f67380085":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89d7609cace3c8-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 16:29:06 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["38"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/ActivitiesTest_TestActivitiesPagination().json b/src/test/resources/fixtures/ActivitiesTest_TestActivitiesPagination().json
index d837539..940da7c 100644
--- a/src/test/resources/fixtures/ActivitiesTest_TestActivitiesPagination().json
+++ b/src/test/resources/fixtures/ActivitiesTest_TestActivitiesPagination().json
@@ -1 +1 @@
-{"ea5d793f07598120d4820d109e50ca2210876935":{"body":"{\"data\":[{\"id\":\"6319f1ae549147ac8d0711dd\",\"created_at\":\"2022-09-08T13:44:14.932000Z\",\"updated_at\":\"2022-09-08T13:44:14.932000Z\",\"type\":\"opened\",\"email\":{\"id\":\"6319f1a266013a90520e1799\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:44:02.782000Z\",\"updated_at\":\"2022-09-08T13:44:04.586000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f1a4f2917b72370e38b5\",\"created_at\":\"2022-09-08T13:44:04.609000Z\",\"updated_at\":\"2022-09-08T13:44:04.609000Z\",\"type\":\"delivered\",\"email\":{\"id\":\"6319f1a266013a90520e1799\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:44:02.782000Z\",\"updated_at\":\"2022-09-08T13:44:04.586000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f1a31fc4de68eb037bda\",\"created_at\":\"2022-09-08T13:44:03.837000Z\",\"updated_at\":\"2022-09-08T13:44:03.837000Z\",\"type\":\"sent\",\"email\":{\"id\":\"6319f1a266013a90520e1799\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:44:02.782000Z\",\"updated_at\":\"2022-09-08T13:44:04.586000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f1a266013a90520e179b\",\"created_at\":\"2022-09-08T13:44:02.832000Z\",\"updated_at\":\"2022-09-08T13:44:02.832000Z\",\"type\":\"queued\",\"email\":{\"id\":\"6319f1a266013a90520e1799\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:44:02.782000Z\",\"updated_at\":\"2022-09-08T13:44:04.586000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f1a266013a90520e179a\",\"created_at\":\"2022-09-08T13:44:02.802000Z\",\"updated_at\":\"2022-09-08T13:44:02.802000Z\",\"type\":\"processed\",\"email\":{\"id\":\"6319f1a266013a90520e1799\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:44:02.782000Z\",\"updated_at\":\"2022-09-08T13:44:04.586000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f1953e8da0e6bc02bc87\",\"created_at\":\"2022-09-08T13:43:49.030000Z\",\"updated_at\":\"2022-09-08T13:43:49.030000Z\",\"type\":\"opened\",\"email\":{\"id\":\"6319f0ca5ca520261f0d0490\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:40:26.639000Z\",\"updated_at\":\"2022-09-08T13:40:27.412000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f1943e8da0e6bc02bc83\",\"created_at\":\"2022-09-08T13:43:48.925000Z\",\"updated_at\":\"2022-09-08T13:43:48.925000Z\",\"type\":\"opened\",\"email\":{\"id\":\"6319f0ca5ca520261f0d0490\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:40:26.639000Z\",\"updated_at\":\"2022-09-08T13:40:27.412000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f0cb5702328ffa0f3179\",\"created_at\":\"2022-09-08T13:40:27.031000Z\",\"updated_at\":\"2022-09-08T13:40:27.031000Z\",\"type\":\"sent\",\"email\":{\"id\":\"6319f0ca5ca520261f0d0490\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:40:26.639000Z\",\"updated_at\":\"2022-09-08T13:40:27.412000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f0cb1a590fa4d80a5ad4\",\"created_at\":\"2022-09-08T13:40:27.427000Z\",\"updated_at\":\"2022-09-08T13:40:27.427000Z\",\"type\":\"delivered\",\"email\":{\"id\":\"6319f0ca5ca520261f0d0490\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:40:26.639000Z\",\"updated_at\":\"2022-09-08T13:40:27.412000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f0ca5ca520261f0d0492\",\"created_at\":\"2022-09-08T13:40:26.674000Z\",\"updated_at\":\"2022-09-08T13:40:26.674000Z\",\"type\":\"queued\",\"email\":{\"id\":\"6319f0ca5ca520261f0d0490\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:40:26.639000Z\",\"updated_at\":\"2022-09-08T13:40:27.412000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}}]}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["74a83b57fd546f6b-ATH"],"content-type":["application/json"],"date":["Wed, 14 Sep 2022 09:52:47 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-15T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200},"9b70dc0e39f8b89c0caf38c1b5f207498d250bd4":{"body":"{\"data\":[{\"id\":\"6319f0ca5ca520261f0d0491\",\"created_at\":\"2022-09-08T13:40:26.655000Z\",\"updated_at\":\"2022-09-08T13:40:26.655000Z\",\"type\":\"processed\",\"email\":{\"id\":\"6319f0ca5ca520261f0d0490\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:40:26.639000Z\",\"updated_at\":\"2022-09-08T13:40:27.412000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319efab75e4045d1d082498\",\"created_at\":\"2022-09-08T13:35:39.248000Z\",\"updated_at\":\"2022-09-08T13:35:39.248000Z\",\"type\":\"opened\",\"email\":{\"id\":\"6319ef9daab262b8ff0bb05f\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:35:25.348000Z\",\"updated_at\":\"2022-09-08T13:35:27.552000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319ef9f2e3630aceb092bf8\",\"created_at\":\"2022-09-08T13:35:27.562000Z\",\"updated_at\":\"2022-09-08T13:35:27.562000Z\",\"type\":\"delivered\",\"email\":{\"id\":\"6319ef9daab262b8ff0bb05f\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:35:25.348000Z\",\"updated_at\":\"2022-09-08T13:35:27.552000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319ef9daab262b8ff0bb061\",\"created_at\":\"2022-09-08T13:35:25.406000Z\",\"updated_at\":\"2022-09-08T13:35:25.406000Z\",\"type\":\"queued\",\"email\":{\"id\":\"6319ef9daab262b8ff0bb05f\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:35:25.348000Z\",\"updated_at\":\"2022-09-08T13:35:27.552000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319ef9daab262b8ff0bb060\",\"created_at\":\"2022-09-08T13:35:25.381000Z\",\"updated_at\":\"2022-09-08T13:35:25.381000Z\",\"type\":\"processed\",\"email\":{\"id\":\"6319ef9daab262b8ff0bb05f\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:35:25.348000Z\",\"updated_at\":\"2022-09-08T13:35:27.552000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319ef9d1699b4a7bd0c9845\",\"created_at\":\"2022-09-08T13:35:25.784000Z\",\"updated_at\":\"2022-09-08T13:35:25.784000Z\",\"type\":\"sent\",\"email\":{\"id\":\"6319ef9daab262b8ff0bb05f\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:35:25.348000Z\",\"updated_at\":\"2022-09-08T13:35:27.552000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"63189f659e10b5b8bd024bb3\",\"created_at\":\"2022-09-07T13:40:53.743000Z\",\"updated_at\":\"2022-09-07T13:40:53.743000Z\",\"type\":\"opened\",\"email\":{\"id\":\"63189f352b118497940f571e\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-07T13:40:05.465000Z\",\"updated_at\":\"2022-09-07T13:40:06.881000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"63189f6592c3b3cc0e0ff483\",\"created_at\":\"2022-09-07T13:40:53.399000Z\",\"updated_at\":\"2022-09-07T13:40:53.399000Z\",\"type\":\"opened\",\"email\":{\"id\":\"63189f27c73648344809f268\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-07T13:39:51.013000Z\",\"updated_at\":\"2022-09-07T13:39:52.117000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"63189f653979e9fd07027ff7\",\"created_at\":\"2022-09-07T13:40:53.198000Z\",\"updated_at\":\"2022-09-07T13:40:53.198000Z\",\"type\":\"opened\",\"email\":{\"id\":\"63189f352f5e68d83201f956\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-07T13:40:05.321000Z\",\"updated_at\":\"2022-09-07T13:40:06.602000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"63189f64c3e842a3df0f2a03\",\"created_at\":\"2022-09-07T13:40:52.612000Z\",\"updated_at\":\"2022-09-07T13:40:52.612000Z\",\"type\":\"opened\",\"email\":{\"id\":\"63189f331a2ce202790d9ce6\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-07T13:40:03.731000Z\",\"updated_at\":\"2022-09-07T13:40:04.870000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}}]}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["74a83b5a9fcf6f6b-ATH"],"content-type":["application/json"],"date":["Wed, 14 Sep 2022 09:52:47 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-15T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["58"]},"statusCode":200}}
\ No newline at end of file
+{"eac0a320682c5317aa46beefc172abd29804f244":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9f7ce3d9c6691d-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 07:32:06 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["31"]},"statusCode":401},"bc3d6676a2655a43e5442b438369331e9d888534":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89ab5479a3691d-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 15:59:01 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["30"]},"statusCode":401},"d780907542e9042f403de1a9f063637e5d82284a":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa06b126a55488f-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:14:42 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["32"]},"statusCode":401},"3a310e4c444fb1ca252bf1b1d9279bb290d09895":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa04ce38f13e32c-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 09:54:06 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["31"]},"statusCode":401},"697ceb43e49f03ed4d7eacb9f2c5793a8cb11778":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa0abeb1d42f437-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:58:58 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["34"]},"statusCode":401},"43d1ee2ced7176d336c4846e67d9654f485b4068":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4fd0aba0b12-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:05 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["45"]},"statusCode":401},"9b70dc0e39f8b89c0caf38c1b5f207498d250bd4":{"body":"{\"data\":[{\"id\":\"6319f0ca5ca520261f0d0491\",\"created_at\":\"2022-09-08T13:40:26.655000Z\",\"updated_at\":\"2022-09-08T13:40:26.655000Z\",\"type\":\"processed\",\"email\":{\"id\":\"6319f0ca5ca520261f0d0490\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:40:26.639000Z\",\"updated_at\":\"2022-09-08T13:40:27.412000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319efab75e4045d1d082498\",\"created_at\":\"2022-09-08T13:35:39.248000Z\",\"updated_at\":\"2022-09-08T13:35:39.248000Z\",\"type\":\"opened\",\"email\":{\"id\":\"6319ef9daab262b8ff0bb05f\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:35:25.348000Z\",\"updated_at\":\"2022-09-08T13:35:27.552000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319ef9f2e3630aceb092bf8\",\"created_at\":\"2022-09-08T13:35:27.562000Z\",\"updated_at\":\"2022-09-08T13:35:27.562000Z\",\"type\":\"delivered\",\"email\":{\"id\":\"6319ef9daab262b8ff0bb05f\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:35:25.348000Z\",\"updated_at\":\"2022-09-08T13:35:27.552000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319ef9daab262b8ff0bb061\",\"created_at\":\"2022-09-08T13:35:25.406000Z\",\"updated_at\":\"2022-09-08T13:35:25.406000Z\",\"type\":\"queued\",\"email\":{\"id\":\"6319ef9daab262b8ff0bb05f\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:35:25.348000Z\",\"updated_at\":\"2022-09-08T13:35:27.552000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319ef9daab262b8ff0bb060\",\"created_at\":\"2022-09-08T13:35:25.381000Z\",\"updated_at\":\"2022-09-08T13:35:25.381000Z\",\"type\":\"processed\",\"email\":{\"id\":\"6319ef9daab262b8ff0bb05f\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:35:25.348000Z\",\"updated_at\":\"2022-09-08T13:35:27.552000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319ef9d1699b4a7bd0c9845\",\"created_at\":\"2022-09-08T13:35:25.784000Z\",\"updated_at\":\"2022-09-08T13:35:25.784000Z\",\"type\":\"sent\",\"email\":{\"id\":\"6319ef9daab262b8ff0bb05f\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:35:25.348000Z\",\"updated_at\":\"2022-09-08T13:35:27.552000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"63189f659e10b5b8bd024bb3\",\"created_at\":\"2022-09-07T13:40:53.743000Z\",\"updated_at\":\"2022-09-07T13:40:53.743000Z\",\"type\":\"opened\",\"email\":{\"id\":\"63189f352b118497940f571e\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-07T13:40:05.465000Z\",\"updated_at\":\"2022-09-07T13:40:06.881000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"63189f6592c3b3cc0e0ff483\",\"created_at\":\"2022-09-07T13:40:53.399000Z\",\"updated_at\":\"2022-09-07T13:40:53.399000Z\",\"type\":\"opened\",\"email\":{\"id\":\"63189f27c73648344809f268\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-07T13:39:51.013000Z\",\"updated_at\":\"2022-09-07T13:39:52.117000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"63189f653979e9fd07027ff7\",\"created_at\":\"2022-09-07T13:40:53.198000Z\",\"updated_at\":\"2022-09-07T13:40:53.198000Z\",\"type\":\"opened\",\"email\":{\"id\":\"63189f352f5e68d83201f956\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-07T13:40:05.321000Z\",\"updated_at\":\"2022-09-07T13:40:06.602000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"63189f64c3e842a3df0f2a03\",\"created_at\":\"2022-09-07T13:40:52.612000Z\",\"updated_at\":\"2022-09-07T13:40:52.612000Z\",\"type\":\"opened\",\"email\":{\"id\":\"63189f331a2ce202790d9ce6\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-07T13:40:03.731000Z\",\"updated_at\":\"2022-09-07T13:40:04.870000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}}]}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["74a83b5a9fcf6f6b-ATH"],"content-type":["application/json"],"date":["Wed, 14 Sep 2022 09:52:47 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-15T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["58"]},"statusCode":200},"63845321ae9be603491ccd12d7ec1c284707c872":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa065b6c8a1e3c8-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:11:02 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["33"]},"statusCode":401},"ea5d793f07598120d4820d109e50ca2210876935":{"body":"{\"data\":[{\"id\":\"6319f1ae549147ac8d0711dd\",\"created_at\":\"2022-09-08T13:44:14.932000Z\",\"updated_at\":\"2022-09-08T13:44:14.932000Z\",\"type\":\"opened\",\"email\":{\"id\":\"6319f1a266013a90520e1799\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:44:02.782000Z\",\"updated_at\":\"2022-09-08T13:44:04.586000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f1a4f2917b72370e38b5\",\"created_at\":\"2022-09-08T13:44:04.609000Z\",\"updated_at\":\"2022-09-08T13:44:04.609000Z\",\"type\":\"delivered\",\"email\":{\"id\":\"6319f1a266013a90520e1799\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:44:02.782000Z\",\"updated_at\":\"2022-09-08T13:44:04.586000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f1a31fc4de68eb037bda\",\"created_at\":\"2022-09-08T13:44:03.837000Z\",\"updated_at\":\"2022-09-08T13:44:03.837000Z\",\"type\":\"sent\",\"email\":{\"id\":\"6319f1a266013a90520e1799\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:44:02.782000Z\",\"updated_at\":\"2022-09-08T13:44:04.586000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f1a266013a90520e179b\",\"created_at\":\"2022-09-08T13:44:02.832000Z\",\"updated_at\":\"2022-09-08T13:44:02.832000Z\",\"type\":\"queued\",\"email\":{\"id\":\"6319f1a266013a90520e1799\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:44:02.782000Z\",\"updated_at\":\"2022-09-08T13:44:04.586000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f1a266013a90520e179a\",\"created_at\":\"2022-09-08T13:44:02.802000Z\",\"updated_at\":\"2022-09-08T13:44:02.802000Z\",\"type\":\"processed\",\"email\":{\"id\":\"6319f1a266013a90520e1799\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:44:02.782000Z\",\"updated_at\":\"2022-09-08T13:44:04.586000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f1953e8da0e6bc02bc87\",\"created_at\":\"2022-09-08T13:43:49.030000Z\",\"updated_at\":\"2022-09-08T13:43:49.030000Z\",\"type\":\"opened\",\"email\":{\"id\":\"6319f0ca5ca520261f0d0490\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:40:26.639000Z\",\"updated_at\":\"2022-09-08T13:40:27.412000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f1943e8da0e6bc02bc83\",\"created_at\":\"2022-09-08T13:43:48.925000Z\",\"updated_at\":\"2022-09-08T13:43:48.925000Z\",\"type\":\"opened\",\"email\":{\"id\":\"6319f0ca5ca520261f0d0490\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:40:26.639000Z\",\"updated_at\":\"2022-09-08T13:40:27.412000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f0cb5702328ffa0f3179\",\"created_at\":\"2022-09-08T13:40:27.031000Z\",\"updated_at\":\"2022-09-08T13:40:27.031000Z\",\"type\":\"sent\",\"email\":{\"id\":\"6319f0ca5ca520261f0d0490\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:40:26.639000Z\",\"updated_at\":\"2022-09-08T13:40:27.412000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f0cb1a590fa4d80a5ad4\",\"created_at\":\"2022-09-08T13:40:27.427000Z\",\"updated_at\":\"2022-09-08T13:40:27.427000Z\",\"type\":\"delivered\",\"email\":{\"id\":\"6319f0ca5ca520261f0d0490\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:40:26.639000Z\",\"updated_at\":\"2022-09-08T13:40:27.412000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}},{\"id\":\"6319f0ca5ca520261f0d0492\",\"created_at\":\"2022-09-08T13:40:26.674000Z\",\"updated_at\":\"2022-09-08T13:40:26.674000Z\",\"type\":\"queued\",\"email\":{\"id\":\"6319f0ca5ca520261f0d0490\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-09-08T13:40:26.639000Z\",\"updated_at\":\"2022-09-08T13:40:27.412000Z\",\"recipient\":{\"id\":\"63189de8c17fea67da00bd1c\",\"email\":\"java@mailersend.com\",\"created_at\":\"2022-09-07T13:34:32.102000Z\",\"updated_at\":\"2022-09-07T13:34:32.102000Z\",\"deleted_at\":\"\"}}}]}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["74a83b57fd546f6b-ATH"],"content-type":["application/json"],"date":["Wed, 14 Sep 2022 09:52:47 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-15T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200},"56ab32fd0aa8f3e0f29342eea8c83093876ff576":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89d8bd0f6941f6-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 16:30:02 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["193"]},"statusCode":401},"b3c6c638e51cda1c051d13af4ce74cd441d5be17":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9f812babc90b12-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 07:35:01 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["33"]},"statusCode":401},"64db6232274aea23cc6b20e54ae2f179c6f3b0aa":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89d7618d2fcef8-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 16:29:06 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["29"]},"statusCode":401},"eca260ee25fb970129986cf3ee3c34365b75693f":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa06b74a9cb979a-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:14:58 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["25"]},"statusCode":401},"a5efd0262cef809613f95968f8d05549291588c8":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9f8085dae0c156-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 07:34:35 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["26"]},"statusCode":401},"2418f299e55cd9c25294d637d6633f95577356f1":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa08bea3dc6f53d-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:37:07 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["40"]},"statusCode":401},"7523fd6327e806db839b6c727599ee1dda4ebe1e":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa06c2f78bae3d0-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:15:28 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["37"]},"statusCode":401},"1b25c097b0e46ed4f2121b711838cb9395c507de":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9fad8459bae3b8-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:05:18 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["40"]},"statusCode":401},"f6597a9a5d2c104e117223b99c8ffb0a2948c23f":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9fadcf489deeea-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:05:30 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["27"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/ActivitiesTest_TestActivityEmailConversion().json b/src/test/resources/fixtures/ActivitiesTest_TestActivityEmailConversion().json
index c8f09db..f215d4d 100644
--- a/src/test/resources/fixtures/ActivitiesTest_TestActivityEmailConversion().json
+++ b/src/test/resources/fixtures/ActivitiesTest_TestActivityEmailConversion().json
@@ -1 +1 @@
-{"ea5d793f07598120d4820d109e50ca2210876935":{"body":"{\"data\":[{\"id\":\"62ff8b75b1ffd57ddb0b5eeb\",\"created_at\":\"2022-08-19T13:09:09.604000Z\",\"updated_at\":\"2022-08-19T13:09:09.604000Z\",\"type\":\"opened\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b697c8c44f1210bfaa2\",\"created_at\":\"2022-08-19T13:08:57.860000Z\",\"updated_at\":\"2022-08-19T13:08:57.860000Z\",\"type\":\"delivered\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b68d05998c8d6012954\",\"created_at\":\"2022-08-19T13:08:56.529000Z\",\"updated_at\":\"2022-08-19T13:08:56.529000Z\",\"type\":\"sent\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b686f6d7fb43c0c4984\",\"created_at\":\"2022-08-19T13:08:56.439000Z\",\"updated_at\":\"2022-08-19T13:08:56.439000Z\",\"type\":\"queued\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b686f6d7fb43c0c4983\",\"created_at\":\"2022-08-19T13:08:56.375000Z\",\"updated_at\":\"2022-08-19T13:08:56.375000Z\",\"type\":\"processed\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}}]}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d32ef0cb806f38-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:19:52 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["55"]},"statusCode":200}}
\ No newline at end of file
+{"bc3d6676a2655a43e5442b438369331e9d888534":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89ab529cdccef8-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 15:59:01 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["43"]},"statusCode":401},"3a310e4c444fb1ca252bf1b1d9279bb290d09895":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa04ce16cdc4813-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 09:54:05 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["31"]},"statusCode":401},"459e4ced8b297486f2c3d163351be4d59505cd46":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9f7ce23c344813-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 07:32:06 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["32"]},"statusCode":401},"7f5d2f1ebe161f5d7af3931f29e6c3c5466322b8":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa0abe94cec8df7-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:58:58 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["26"]},"statusCode":401},"43d1ee2ced7176d336c4846e67d9654f485b4068":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4fb497294ad-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:05 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["28"]},"statusCode":401},"63845321ae9be603491ccd12d7ec1c284707c872":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa065b4ad934610-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:11:02 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["35"]},"statusCode":401},"8f8ed130d5e6addc7217862642528f7f9e4d56a4":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89d75f9b8d48a6-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 16:29:05 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["35"]},"statusCode":401},"ea5d793f07598120d4820d109e50ca2210876935":{"body":"{\"data\":[{\"id\":\"62ff8b75b1ffd57ddb0b5eeb\",\"created_at\":\"2022-08-19T13:09:09.604000Z\",\"updated_at\":\"2022-08-19T13:09:09.604000Z\",\"type\":\"opened\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b697c8c44f1210bfaa2\",\"created_at\":\"2022-08-19T13:08:57.860000Z\",\"updated_at\":\"2022-08-19T13:08:57.860000Z\",\"type\":\"delivered\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b68d05998c8d6012954\",\"created_at\":\"2022-08-19T13:08:56.529000Z\",\"updated_at\":\"2022-08-19T13:08:56.529000Z\",\"type\":\"sent\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b686f6d7fb43c0c4984\",\"created_at\":\"2022-08-19T13:08:56.439000Z\",\"updated_at\":\"2022-08-19T13:08:56.439000Z\",\"type\":\"queued\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b686f6d7fb43c0c4983\",\"created_at\":\"2022-08-19T13:08:56.375000Z\",\"updated_at\":\"2022-08-19T13:08:56.375000Z\",\"type\":\"processed\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}}]}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d32ef0cb806f38-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:19:52 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["55"]},"statusCode":200},"56ab32fd0aa8f3e0f29342eea8c83093876ff576":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89d8bab81e4842-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 16:30:01 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["36"]},"statusCode":401},"b3c6c638e51cda1c051d13af4ce74cd441d5be17":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9f8129b87df55c-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 07:35:01 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["46"]},"statusCode":401},"eca260ee25fb970129986cf3ee3c34365b75693f":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa06b72dc4ce3b8-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:14:57 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["39"]},"statusCode":401},"a5efd0262cef809613f95968f8d05549291588c8":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9f80843eee692f-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 07:34:34 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["24"]},"statusCode":401},"bf2e6e4fe146c31f1e939c8366e812cd3c5ba62f":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa06b105e014813-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:14:42 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["27"]},"statusCode":401},"2418f299e55cd9c25294d637d6633f95577356f1":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa08be86ce5979a-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:37:07 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["23"]},"statusCode":401},"7523fd6327e806db839b6c727599ee1dda4ebe1e":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa06c2d8a2f2f4e-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:15:27 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["26"]},"statusCode":401},"1b25c097b0e46ed4f2121b711838cb9395c507de":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9fad828bd4055d-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:05:17 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["28"]},"statusCode":401},"f6597a9a5d2c104e117223b99c8ffb0a2948c23f":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9fadcd7d11e3b8-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:05:29 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["35"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/ActivitiesTest_TestGetActivities().json b/src/test/resources/fixtures/ActivitiesTest_TestGetActivities().json
index 269e766..37f6644 100644
--- a/src/test/resources/fixtures/ActivitiesTest_TestGetActivities().json
+++ b/src/test/resources/fixtures/ActivitiesTest_TestGetActivities().json
@@ -1 +1 @@
-{"e54a370550be7071afd53c85b38b9e3d4bb3bffb":{"body":"{\"data\":[{\"id\":\"62ff8b75b1ffd57ddb0b5eeb\",\"created_at\":\"2022-08-19T13:09:09.604000Z\",\"updated_at\":\"2022-08-19T13:09:09.604000Z\",\"type\":\"opened\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b697c8c44f1210bfaa2\",\"created_at\":\"2022-08-19T13:08:57.860000Z\",\"updated_at\":\"2022-08-19T13:08:57.860000Z\",\"type\":\"delivered\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b68d05998c8d6012954\",\"created_at\":\"2022-08-19T13:08:56.529000Z\",\"updated_at\":\"2022-08-19T13:08:56.529000Z\",\"type\":\"sent\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b686f6d7fb43c0c4984\",\"created_at\":\"2022-08-19T13:08:56.439000Z\",\"updated_at\":\"2022-08-19T13:08:56.439000Z\",\"type\":\"queued\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b686f6d7fb43c0c4983\",\"created_at\":\"2022-08-19T13:08:56.375000Z\",\"updated_at\":\"2022-08-19T13:08:56.375000Z\",\"type\":\"processed\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}}]}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d3250de9ccfd5e-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:13:08 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
+{"5880f0425a8fb8a32c43ebd0cc21b01c8b5e7de9":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa06b0e3a724842-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:14:41 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["42"]},"statusCode":401},"a1f4e3a3f025f76540dffa935ff22819adad0ce1":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa06b70cce716a5-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:14:57 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["32"]},"statusCode":401},"2e4e7b8d2f0500eeba1bd3b7f772410dc7395075":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9f7ce068456914-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 07:32:05 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["40"]},"statusCode":401},"d074f4e39a994c61498b3735209d6459b48d8685":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9f80829da64813-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 07:34:34 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["28"]},"statusCode":401},"0201ad2ef478381c035779c634fb7e9fe75ed3f0":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89d8b8fdfef4f9-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 16:30:01 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["26"]},"statusCode":401},"ac818476df6246bc61970bbfa13a03dbf5f652eb":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9fad80d9d3e3d0-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:05:17 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["27"]},"statusCode":401},"48c43ffcf0fe6ef9e4655ef9f8b464bbe4250b23":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa08be69ce04610-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:37:07 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["29"]},"statusCode":401},"17c0becd7088d1cd4e7e23a73776e625a99e9dda":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89d75dac2c4891-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 16:29:05 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["45"]},"statusCode":401},"e4206ede86a5e5fa042eb8a078b1212af030147d":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa06c2b7813e3bc-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:15:27 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["22"]},"statusCode":401},"92217c8c50150c9b2a2ecc8f67e5c2558794bd1c":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9f8127fdcee6de-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 07:35:01 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["30"]},"statusCode":401},"e54a370550be7071afd53c85b38b9e3d4bb3bffb":{"body":"{\"data\":[{\"id\":\"62ff8b75b1ffd57ddb0b5eeb\",\"created_at\":\"2022-08-19T13:09:09.604000Z\",\"updated_at\":\"2022-08-19T13:09:09.604000Z\",\"type\":\"opened\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b697c8c44f1210bfaa2\",\"created_at\":\"2022-08-19T13:08:57.860000Z\",\"updated_at\":\"2022-08-19T13:08:57.860000Z\",\"type\":\"delivered\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b68d05998c8d6012954\",\"created_at\":\"2022-08-19T13:08:56.529000Z\",\"updated_at\":\"2022-08-19T13:08:56.529000Z\",\"type\":\"sent\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b686f6d7fb43c0c4984\",\"created_at\":\"2022-08-19T13:08:56.439000Z\",\"updated_at\":\"2022-08-19T13:08:56.439000Z\",\"type\":\"queued\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b686f6d7fb43c0c4983\",\"created_at\":\"2022-08-19T13:08:56.375000Z\",\"updated_at\":\"2022-08-19T13:08:56.375000Z\",\"type\":\"processed\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}}]}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d3250de9ccfd5e-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:13:08 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200},"de179349a95f66d29339d1fde2db5a8910eda92e":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89ab50aae32f4e-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 15:59:01 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["25"]},"statusCode":401},"947b5e811ee1ad8f71e33846999c3533fbae8a5f":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9fadcbc97fe3d1-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:05:29 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["26"]},"statusCode":401},"281cfa6e19007547c13bb01cc6dff42ccfac4e13":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa04cdf6a52750d-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 09:54:05 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["55"]},"statusCode":401},"6c92e87519e1b7ef77bcabf72668cdee9e237b75":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa065b1ff4ff437-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:11:02 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["28"]},"statusCode":401},"98c7d18ecbe60914d2cfe75f91060b0a61fb0041":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4f968385910-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:05 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["29"]},"statusCode":401},"6093570cc4f226a080c7685e1a50f1feb7c8cd9f":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa0abe71f0f4610-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:58:57 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["24"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/ActivitiesTest_TestSingleActivity().json b/src/test/resources/fixtures/ActivitiesTest_TestSingleActivity().json
index 21c69a3..562f996 100644
--- a/src/test/resources/fixtures/ActivitiesTest_TestSingleActivity().json
+++ b/src/test/resources/fixtures/ActivitiesTest_TestSingleActivity().json
@@ -1 +1 @@
-{"ea5d793f07598120d4820d109e50ca2210876935":{"body":"{\"data\":[{\"id\":\"62ff8b75b1ffd57ddb0b5eeb\",\"created_at\":\"2022-08-19T13:09:09.604000Z\",\"updated_at\":\"2022-08-19T13:09:09.604000Z\",\"type\":\"opened\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b697c8c44f1210bfaa2\",\"created_at\":\"2022-08-19T13:08:57.860000Z\",\"updated_at\":\"2022-08-19T13:08:57.860000Z\",\"type\":\"delivered\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b68d05998c8d6012954\",\"created_at\":\"2022-08-19T13:08:56.529000Z\",\"updated_at\":\"2022-08-19T13:08:56.529000Z\",\"type\":\"sent\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b686f6d7fb43c0c4984\",\"created_at\":\"2022-08-19T13:08:56.439000Z\",\"updated_at\":\"2022-08-19T13:08:56.439000Z\",\"type\":\"queued\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b686f6d7fb43c0c4983\",\"created_at\":\"2022-08-19T13:08:56.375000Z\",\"updated_at\":\"2022-08-19T13:08:56.375000Z\",\"type\":\"processed\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}}]}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d32ebebff96f31-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:19:44 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["56"]},"statusCode":200}}
\ No newline at end of file
+{"bc3d6676a2655a43e5442b438369331e9d888534":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89ab518aa0a10f-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 15:59:01 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["50"]},"statusCode":401},"3a310e4c444fb1ca252bf1b1d9279bb290d09895":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa04ce07b9262e8-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 09:54:05 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["26"]},"statusCode":401},"459e4ced8b297486f2c3d163351be4d59505cd46":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9f7ce16911e3b0-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 07:32:06 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["31"]},"statusCode":401},"7f5d2f1ebe161f5d7af3931f29e6c3c5466322b8":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa0abe81fc7b2a2-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:58:58 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["39"]},"statusCode":401},"43d1ee2ced7176d336c4846e67d9654f485b4068":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4fa4d0748a6-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:05 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["32"]},"statusCode":401},"63845321ae9be603491ccd12d7ec1c284707c872":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa065b32d62f927-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:11:02 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["37"]},"statusCode":401},"8f8ed130d5e6addc7217862642528f7f9e4d56a4":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89d75ebf20cc1e-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 16:29:05 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["32"]},"statusCode":401},"ea5d793f07598120d4820d109e50ca2210876935":{"body":"{\"data\":[{\"id\":\"62ff8b75b1ffd57ddb0b5eeb\",\"created_at\":\"2022-08-19T13:09:09.604000Z\",\"updated_at\":\"2022-08-19T13:09:09.604000Z\",\"type\":\"opened\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b697c8c44f1210bfaa2\",\"created_at\":\"2022-08-19T13:08:57.860000Z\",\"updated_at\":\"2022-08-19T13:08:57.860000Z\",\"type\":\"delivered\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b68d05998c8d6012954\",\"created_at\":\"2022-08-19T13:08:56.529000Z\",\"updated_at\":\"2022-08-19T13:08:56.529000Z\",\"type\":\"sent\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b686f6d7fb43c0c4984\",\"created_at\":\"2022-08-19T13:08:56.439000Z\",\"updated_at\":\"2022-08-19T13:08:56.439000Z\",\"type\":\"queued\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"62ff8b686f6d7fb43c0c4983\",\"created_at\":\"2022-08-19T13:08:56.375000Z\",\"updated_at\":\"2022-08-19T13:08:56.375000Z\",\"type\":\"processed\",\"email\":{\"id\":\"62ff8b686f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2022-08-19T13:08:56.358000Z\",\"updated_at\":\"2022-08-19T13:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"john@mailerlite.com\",\"created_at\":\"2022-06-09T15:30:19.265000Z\",\"updated_at\":\"2022-06-09T15:30:19.265000Z\",\"deleted_at\":\"\"}}}]}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d32ebebff96f31-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:19:44 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["56"]},"statusCode":200},"56ab32fd0aa8f3e0f29342eea8c83093876ff576":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89d8b9d957b17c-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 16:30:01 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["27"]},"statusCode":401},"b3c6c638e51cda1c051d13af4ce74cd441d5be17":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9f8128db0be3bd-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 07:35:01 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["41"]},"statusCode":401},"eca260ee25fb970129986cf3ee3c34365b75693f":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa06b71ef7fcef8-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:14:57 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["26"]},"statusCode":401},"a5efd0262cef809613f95968f8d05549291588c8":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9f80837cbdf4f9-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 07:34:34 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["24"]},"statusCode":401},"bf2e6e4fe146c31f1e939c8366e812cd3c5ba62f":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa06b0f3ff2e6de-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:14:41 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["34"]},"statusCode":401},"2418f299e55cd9c25294d637d6633f95577356f1":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa08be789c58e38-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:37:07 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["27"]},"statusCode":401},"7523fd6327e806db839b6c727599ee1dda4ebe1e":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa06c2c6bc10b12-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:15:27 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["26"]},"statusCode":401},"1b25c097b0e46ed4f2121b711838cb9395c507de":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9fad81b80e16a5-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:05:17 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["24"]},"statusCode":401},"f6597a9a5d2c104e117223b99c8ffb0a2948c23f":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9fadcca972d92d-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:05:29 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["24"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/BlocklistMonitoringTest_createMonitorTest().json b/src/test/resources/fixtures/BlocklistMonitoringTest_createMonitorTest().json
new file mode 100644
index 0000000..22ec366
--- /dev/null
+++ b/src/test/resources/fixtures/BlocklistMonitoringTest_createMonitorTest().json
@@ -0,0 +1 @@
+{"ecb81e1514297b07295d867799aad8396a541813":{"body":"{\"data\":{\"id\":\"blocklist-monitor-id-test\",\"name\":\"test-domain.com\",\"address\":\"test-domain.com\",\"type\":\"domain\",\"in_progress\":true,\"notify\":false,\"blocklisted\":false,\"last_checks_count\":0,\"last_check\":null,\"next_check\":null,\"has_children\":false,\"children_count\":0,\"forwards\":[],\"hits\":[],\"created_at\":\"2023-05-01T10:00:00.000000Z\",\"updated_at\":\"2023-05-01T10:00:00.000000Z\"}}","headers":{":status":["201"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":201}}
diff --git a/src/test/resources/fixtures/BlocklistMonitoringTest_deleteMonitorTest().json b/src/test/resources/fixtures/BlocklistMonitoringTest_deleteMonitorTest().json
new file mode 100644
index 0000000..cfe371f
--- /dev/null
+++ b/src/test/resources/fixtures/BlocklistMonitoringTest_deleteMonitorTest().json
@@ -0,0 +1 @@
+{"d9098486ca8fb5933a33b6d62cbc7e6e0ae66356":{"body":"","headers":{":status":["204"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":204}}
diff --git a/src/test/resources/fixtures/BlocklistMonitoringTest_getMonitorTest().json b/src/test/resources/fixtures/BlocklistMonitoringTest_getMonitorTest().json
new file mode 100644
index 0000000..480c3da
--- /dev/null
+++ b/src/test/resources/fixtures/BlocklistMonitoringTest_getMonitorTest().json
@@ -0,0 +1 @@
+{"0dfc5f4fc9a90e3d2e740f0b779576e7ea09c6f0":{"body":"{\"data\":{\"id\":\"blocklist-monitor-id-test\",\"name\":\"test-domain.com\",\"address\":\"test-domain.com\",\"type\":\"domain\",\"in_progress\":false,\"notify\":true,\"blocklisted\":false,\"last_checks_count\":5,\"last_check\":\"2023-06-01T10:00:00.000000Z\",\"next_check\":\"2023-06-02T10:00:00.000000Z\",\"has_children\":false,\"children_count\":0,\"forwards\":[],\"hits\":[],\"created_at\":\"2023-05-01T10:00:00.000000Z\",\"updated_at\":\"2023-06-01T10:00:00.000000Z\"}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
diff --git a/src/test/resources/fixtures/BlocklistMonitoringTest_getMonitorsTest().json b/src/test/resources/fixtures/BlocklistMonitoringTest_getMonitorsTest().json
new file mode 100644
index 0000000..2b940ae
--- /dev/null
+++ b/src/test/resources/fixtures/BlocklistMonitoringTest_getMonitorsTest().json
@@ -0,0 +1 @@
+{"3f4f80ef8c0bfe075412690fb11ea5ed68ee9c78":{"body":"{\"data\":[{\"id\":\"blocklist-monitor-id-test\",\"name\":\"test-domain.com\",\"address\":\"test-domain.com\",\"type\":\"domain\",\"in_progress\":false,\"notify\":true,\"blocklisted\":false,\"last_checks_count\":5,\"last_check\":\"2023-06-01T10:00:00.000000Z\",\"next_check\":\"2023-06-02T10:00:00.000000Z\",\"has_children\":false,\"children_count\":0,\"forwards\":[],\"created_at\":\"2023-05-01T10:00:00.000000Z\",\"updated_at\":\"2023-06-01T10:00:00.000000Z\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/blocklist-monitoring?page=1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/blocklist-monitoring?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[{\"url\":null,\"label\":\"« Previous\",\"active\":false},{\"url\":\"https:\\/\\/api.mailersend.com\\/v1\\/blocklist-monitoring?page=1\",\"label\":\"1\",\"active\":true},{\"url\":null,\"label\":\"Next »\",\"active\":false}],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/blocklist-monitoring\",\"per_page\":25,\"to\":1,\"total\":1}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
diff --git a/src/test/resources/fixtures/BlocklistMonitoringTest_updateMonitorTest().json b/src/test/resources/fixtures/BlocklistMonitoringTest_updateMonitorTest().json
new file mode 100644
index 0000000..b05fd93
--- /dev/null
+++ b/src/test/resources/fixtures/BlocklistMonitoringTest_updateMonitorTest().json
@@ -0,0 +1 @@
+{"31beedc5f84fcdc1979da40fbfd882f428e262cc":{"body":"{\"data\":{\"id\":\"blocklist-monitor-id-test\",\"name\":\"updated-monitor\",\"address\":\"test-domain.com\",\"type\":\"domain\",\"in_progress\":false,\"notify\":true,\"blocklisted\":false,\"last_checks_count\":5,\"last_check\":\"2023-06-01T10:00:00.000000Z\",\"next_check\":\"2023-06-02T10:00:00.000000Z\",\"has_children\":false,\"children_count\":0,\"forwards\":[],\"hits\":[],\"created_at\":\"2023-05-01T10:00:00.000000Z\",\"updated_at\":\"2023-06-01T10:00:00.000000Z\"}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
diff --git a/src/test/resources/fixtures/DmarcMonitoringTest_GetReportSourcesTest().json b/src/test/resources/fixtures/DmarcMonitoringTest_GetReportSourcesTest().json
index e9f9fc3..2c09f96 100644
--- a/src/test/resources/fixtures/DmarcMonitoringTest_GetReportSourcesTest().json
+++ b/src/test/resources/fixtures/DmarcMonitoringTest_GetReportSourcesTest().json
@@ -1 +1 @@
-{"99b5f74465279a3586711ec73a03d69826efea5c":{"body":"{\"data\":[{\"report_source\":\"google.com\",\"reports\":42},{\"report_source\":\"microsoft.com\",\"reports\":17}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/dmarc-monitoring\\/dmarc-monitor-id-test\\/report-sources?page=1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/dmarc-monitoring\\/dmarc-monitor-id-test\\/report-sources?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/dmarc-monitoring\\/dmarc-monitor-id-test\\/report-sources\",\"per_page\":25,\"to\":2,\"total\":2}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
+{"aa450ceaea39a9586f69c661ef550976f8b347e0":{"body":"{\"data\":[{\"report_source\":\"google.com\",\"reports\":42},{\"report_source\":\"microsoft.com\",\"reports\":17}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/dmarc-monitoring\\/dmarc-monitor-id-test\\/report-sources?page=1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/dmarc-monitoring\\/dmarc-monitor-id-test\\/report-sources?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/dmarc-monitoring\\/dmarc-monitor-id-test\\/report-sources\",\"per_page\":25,\"to\":2,\"total\":2}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
diff --git a/src/test/resources/fixtures/DmarcMonitoringTest_getReportSourcesWithStatusTest().json b/src/test/resources/fixtures/DmarcMonitoringTest_getReportSourcesWithStatusTest().json
new file mode 100644
index 0000000..be268a5
--- /dev/null
+++ b/src/test/resources/fixtures/DmarcMonitoringTest_getReportSourcesWithStatusTest().json
@@ -0,0 +1 @@
+{"5e876b589680a26e1b3878a6b28d10c64b187e4a":{"body":"{\"data\":[{\"report_source\":\"google.com\",\"reports\":38},{\"report_source\":\"yahoo.com\",\"reports\":12}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/dmarc-monitoring\\/dmarc-monitor-id-test\\/report-sources?page=1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/dmarc-monitoring\\/dmarc-monitor-id-test\\/report-sources?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/dmarc-monitoring\\/dmarc-monitor-id-test\\/report-sources\",\"per_page\":25,\"to\":2,\"total\":2}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
diff --git a/src/test/resources/fixtures/DomainsTest_testUpdateDomainSettingsAllFields().json b/src/test/resources/fixtures/DomainsTest_testUpdateDomainSettingsAllFields().json
new file mode 100644
index 0000000..c381c1b
--- /dev/null
+++ b/src/test/resources/fixtures/DomainsTest_testUpdateDomainSettingsAllFields().json
@@ -0,0 +1 @@
+{"ac249b720534e764d98b06a7f6cce7d4226ff1bd":{"body":"{\"data\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"dkim\":false,\"spf\":false,\"tracking\":true,\"is_verified\":true,\"is_cname_verified\":false,\"is_dns_active\":false,\"is_cname_active\":false,\"is_tracking_allowed\":true,\"has_not_queued_messages\":false,\"not_queued_messages_count\":0,\"domain_settings\":{\"send_paused\":true,\"track_clicks\":true,\"track_opens\":true,\"track_unsubscribe\":true,\"track_unsubscribe_html\":\"\\u003cp\\u003eUnsubscribe\\u003c/p\\u003e\",\"track_unsubscribe_html_enabled\":true,\"track_unsubscribe_plain\":\"Click here to unsubscribe\",\"track_unsubscribe_plain_enabled\":true,\"track_content\":true,\"custom_tracking_enabled\":true,\"custom_tracking_subdomain\":\"email\",\"return_path_subdomain\":\"mta\",\"inbound_routing_enabled\":false,\"inbound_routing_subdomain\":\"\",\"precedence_bulk\":false,\"ignore_duplicated_recipients\":true},\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-09-14T09:54:40.000000Z\"}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["57"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_ScheduleEmailTest().json b/src/test/resources/fixtures/EmailSendTest_ScheduleEmailTest().json
index 4565324..8771a06 100644
--- a/src/test/resources/fixtures/EmailSendTest_ScheduleEmailTest().json
+++ b/src/test/resources/fixtures/EmailSendTest_ScheduleEmailTest().json
@@ -1 +1 @@
-{"d4977e990b2f2ac2d8e65aa2c9661b4ef22636b5":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"content-type":["text/html; charset\u003dUTF-8"],"x-message-id":["test-schedule-email-message-id"]},"statusCode":202},"6b15cf69672ee532a9f601876778851cc4ca3135":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["755442149ddbeea0-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Wed, 05 Oct 2022 06:56:34 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-10-06T00:00:00Z"],"x-message-id":["633d2aa226762ac1d30457e0"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["118"]},"statusCode":202},"e4a0bcf8b4e53b4dcfb4d96b2db3d8a0054a92f2":{"body":"{\"message\":\"The send_at must be a date before or equal to 2024-08-04 12:24:25.\",\"errors\":{\"send_at\":[\"The send_at must be a date before or equal to 2024-08-04 12:24:25.\"]}}","headers":{":status":["422"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ce134f316f56-ATH"],"content-type":["application/json"],"date":["Thu, 01 Aug 2024 12:24:25 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"]},"statusCode":422},"4f6a751939688d9c22a55807b9b1717ea74552f7":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5d0d95b7f7176-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Thu, 01 Aug 2024 12:26:18 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"],"x-message-id":["66ab7eea1101995a278ad874"]},"statusCode":202}}
\ No newline at end of file
+{"d4977e990b2f2ac2d8e65aa2c9661b4ef22636b5":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"content-type":["text/html; charset\u003dUTF-8"],"x-message-id":["test-schedule-email-message-id"]},"statusCode":202},"72f3a954c8b96196843233108032ec304e15b904":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f6782e96c55c640-LIS"],"content-type":["application/json"],"date":["Mon, 04 May 2026 12:29:30 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["37"]},"statusCode":401},"6b15cf69672ee532a9f601876778851cc4ca3135":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["755442149ddbeea0-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Wed, 05 Oct 2022 06:56:34 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-10-06T00:00:00Z"],"x-message-id":["633d2aa226762ac1d30457e0"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["118"]},"statusCode":202},"e4a0bcf8b4e53b4dcfb4d96b2db3d8a0054a92f2":{"body":"{\"message\":\"The send_at must be a date before or equal to 2024-08-04 12:24:25.\",\"errors\":{\"send_at\":[\"The send_at must be a date before or equal to 2024-08-04 12:24:25.\"]}}","headers":{":status":["422"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ce134f316f56-ATH"],"content-type":["application/json"],"date":["Thu, 01 Aug 2024 12:24:25 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"]},"statusCode":422},"4f6a751939688d9c22a55807b9b1717ea74552f7":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5d0d95b7f7176-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Thu, 01 Aug 2024 12:26:18 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"],"x-message-id":["66ab7eea1101995a278ad874"]},"statusCode":202}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_TestBccSend().json b/src/test/resources/fixtures/EmailSendTest_TestBccSend().json
index 21486c0..07e106b 100644
--- a/src/test/resources/fixtures/EmailSendTest_TestBccSend().json
+++ b/src/test/resources/fixtures/EmailSendTest_TestBccSend().json
@@ -1 +1 @@
-{"7c6a2eadf3785e3e9a7328cfd736ce3fca2e9c9b":{"body":"{\"message\":\"There are some warnings for your request.\",\"warnings\":[{\"type\":\"SOME_SUPPRESSED\",\"warning\":\"Some of the recipients have been suppressed.\",\"recipients\":[{\"email\":\"bcc@test-sdk.com\",\"name\":\"BCC Email\",\"reasons\":[\"blocklisted\"]}]}]}","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca393b706f3d-ATH"],"content-type":["application/json"],"date":["Thu, 01 Aug 2024 12:21:47 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"],"x-message-id":["66ab7ddb155d91c93d446209"]},"statusCode":202},"13e265f3e3ef5a5772f3d6f00236208e5fba2762":{"body":"{\"message\":\"There are some warnings for your request.\",\"warnings\":[{\"type\":\"SOME_SUPPRESSED\",\"warning\":\"Some of the recipients have been suppressed.\",\"recipients\":[{\"email\":\"bcc@test-sdk.com\",\"name\":\"BCC Email\",\"reasons\":[\"blocklisted\"]}]}]}","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fdab33d8b38d0-ATH"],"content-type":["application/json"],"date":["Wed, 07 Sep 2022 13:40:06 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-message-id":["63189f366eea0254cd05351a"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["118"]},"statusCode":202}}
\ No newline at end of file
+{"7c6a2eadf3785e3e9a7328cfd736ce3fca2e9c9b":{"body":"{\"message\":\"There are some warnings for your request.\",\"warnings\":[{\"type\":\"SOME_SUPPRESSED\",\"warning\":\"Some of the recipients have been suppressed.\",\"recipients\":[{\"email\":\"bcc@test-sdk.com\",\"name\":\"BCC Email\",\"reasons\":[\"blocklisted\"]}]}]}","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca393b706f3d-ATH"],"content-type":["application/json"],"date":["Thu, 01 Aug 2024 12:21:47 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"],"x-message-id":["66ab7ddb155d91c93d446209"]},"statusCode":202},"13e265f3e3ef5a5772f3d6f00236208e5fba2762":{"body":"{\"message\":\"There are some warnings for your request.\",\"warnings\":[{\"type\":\"SOME_SUPPRESSED\",\"warning\":\"Some of the recipients have been suppressed.\",\"recipients\":[{\"email\":\"bcc@test-sdk.com\",\"name\":\"BCC Email\",\"reasons\":[\"blocklisted\"]}]}]}","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fdab33d8b38d0-ATH"],"content-type":["application/json"],"date":["Wed, 07 Sep 2022 13:40:06 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-message-id":["63189f366eea0254cd05351a"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["118"]},"statusCode":202},"ee9967c8de6d09e45cc8b5360aaecb481afb26ae":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f6782eb48b8f369-LIS"],"content-type":["application/json"],"date":["Mon, 04 May 2026 12:29:30 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["28"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_TestBulkSendStatus().json b/src/test/resources/fixtures/EmailSendTest_TestBulkSendStatus().json
index aa3ebbb..290adf9 100644
--- a/src/test/resources/fixtures/EmailSendTest_TestBulkSendStatus().json
+++ b/src/test/resources/fixtures/EmailSendTest_TestBulkSendStatus().json
@@ -1 +1 @@
-{"37b5f50e96caf7fc67c73a1adb5f10d0423dafd7":{"body":"{\"data\":{\"id\":\"63189f33fad6a72e7b046337\",\"state\":\"queued\",\"total_recipients_count\":2,\"suppressed_recipients_count\":0,\"suppressed_recipients\":null,\"validation_errors_count\":0,\"validation_errors\":null,\"messages_id\":null,\"created_at\":\"2022-09-07T13:40:03.225000Z\",\"updated_at\":\"2022-09-07T13:40:03.225000Z\"}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fdaa12ae8fd5e-ATH"],"content-type":["application/json"],"date":["Wed, 07 Sep 2022 13:40:03 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"]},"statusCode":200},"8f0780761a780ae068a00da370e58cf5d23a6404":{"body":"{\"data\":{\"id\":\"66ab7dd85c94bed1378f8af0\",\"state\":\"queued\",\"total_recipients_count\":2,\"suppressed_recipients_count\":0,\"suppressed_recipients\":null,\"validation_errors_count\":0,\"validation_errors\":null,\"messages_id\":null,\"created_at\":\"2024-08-01T12:21:44.000000Z\",\"updated_at\":\"2024-08-01T12:21:44.000000Z\"}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca291a97eeb0-ATH"],"content-type":["application/json"],"date":["Thu, 01 Aug 2024 12:21:44 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"]},"statusCode":200},"4608d385c6f46ad4f9fbb8bc08f9d1e71e0faea0":{"body":"{\"message\":\"The bulk email is being processed.\",\"bulk_email_id\":\"66ab7dd85c94bed1378f8af0\"}","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca266dc9eeb0-ATH"],"content-type":["application/json"],"date":["Thu, 01 Aug 2024 12:21:44 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"]},"statusCode":202},"8bea544a494d82e7caa837ef07dc6ae54aaa8e5a":{"body":"{\"message\":\"The bulk email is being processed.\",\"bulk_email_id\":\"63189f33fad6a72e7b046337\"}","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fda9ef84dfd5e-ATH"],"content-type":["application/json"],"date":["Wed, 07 Sep 2022 13:40:03 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-ratelimit-limit":["10"],"x-ratelimit-remaining":["9"]},"statusCode":202}}
\ No newline at end of file
+{"37b5f50e96caf7fc67c73a1adb5f10d0423dafd7":{"body":"{\"data\":{\"id\":\"63189f33fad6a72e7b046337\",\"state\":\"queued\",\"total_recipients_count\":2,\"suppressed_recipients_count\":0,\"suppressed_recipients\":null,\"validation_errors_count\":0,\"validation_errors\":null,\"messages_id\":null,\"created_at\":\"2022-09-07T13:40:03.225000Z\",\"updated_at\":\"2022-09-07T13:40:03.225000Z\"}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fdaa12ae8fd5e-ATH"],"content-type":["application/json"],"date":["Wed, 07 Sep 2022 13:40:03 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"]},"statusCode":200},"4773373f97ed04a6030f29a7d895bcca9262847e":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f6782e35ce76932-LIS"],"content-type":["application/json"],"date":["Mon, 04 May 2026 12:29:29 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["30"]},"statusCode":401},"8f0780761a780ae068a00da370e58cf5d23a6404":{"body":"{\"data\":{\"id\":\"66ab7dd85c94bed1378f8af0\",\"state\":\"queued\",\"total_recipients_count\":2,\"suppressed_recipients_count\":0,\"suppressed_recipients\":null,\"validation_errors_count\":0,\"validation_errors\":null,\"messages_id\":null,\"created_at\":\"2024-08-01T12:21:44.000000Z\",\"updated_at\":\"2024-08-01T12:21:44.000000Z\"}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca291a97eeb0-ATH"],"content-type":["application/json"],"date":["Thu, 01 Aug 2024 12:21:44 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"]},"statusCode":200},"4608d385c6f46ad4f9fbb8bc08f9d1e71e0faea0":{"body":"{\"message\":\"The bulk email is being processed.\",\"bulk_email_id\":\"66ab7dd85c94bed1378f8af0\"}","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca266dc9eeb0-ATH"],"content-type":["application/json"],"date":["Thu, 01 Aug 2024 12:21:44 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"]},"statusCode":202},"8bea544a494d82e7caa837ef07dc6ae54aaa8e5a":{"body":"{\"message\":\"The bulk email is being processed.\",\"bulk_email_id\":\"63189f33fad6a72e7b046337\"}","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fda9ef84dfd5e-ATH"],"content-type":["application/json"],"date":["Wed, 07 Sep 2022 13:40:03 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-ratelimit-limit":["10"],"x-ratelimit-remaining":["9"]},"statusCode":202}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_TestCcSend().json b/src/test/resources/fixtures/EmailSendTest_TestCcSend().json
index 4b5cbaa..737e67f 100644
--- a/src/test/resources/fixtures/EmailSendTest_TestCcSend().json
+++ b/src/test/resources/fixtures/EmailSendTest_TestCcSend().json
@@ -1 +1 @@
-{"15f5de7b423db5fa23acaaa01686aa62d58f5cfa":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca32094f7184-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Thu, 01 Aug 2024 12:21:46 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"],"x-message-id":["66ab7dda5bd70b2cf6fc8995"]},"statusCode":202},"ec4d2d45acec574fe06fd7fe8fd5a135e10cce16":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fdaaa7bd938cb-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Wed, 07 Sep 2022 13:40:05 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-message-id":["63189f35c55e2c48af0f453b"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["115"]},"statusCode":202}}
\ No newline at end of file
+{"15f5de7b423db5fa23acaaa01686aa62d58f5cfa":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca32094f7184-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Thu, 01 Aug 2024 12:21:46 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"],"x-message-id":["66ab7dda5bd70b2cf6fc8995"]},"statusCode":202},"01aa41b46b33ddbb436ab8c1cbf4e7b4e563889e":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f6782e70f86692c-LIS"],"content-type":["application/json"],"date":["Mon, 04 May 2026 12:29:30 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["38"]},"statusCode":401},"ec4d2d45acec574fe06fd7fe8fd5a135e10cce16":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fdaaa7bd938cb-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Wed, 07 Sep 2022 13:40:05 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-message-id":["63189f35c55e2c48af0f453b"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["115"]},"statusCode":202}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_TestEmailWithAttachment().json b/src/test/resources/fixtures/EmailSendTest_TestEmailWithAttachment().json
index 31b3002..5fa6c1b 100644
--- a/src/test/resources/fixtures/EmailSendTest_TestEmailWithAttachment().json
+++ b/src/test/resources/fixtures/EmailSendTest_TestEmailWithAttachment().json
@@ -1 +1 @@
-{"872ed332468f4b2427c07accf4e75f1353d64c4d":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca303f6738c9-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Thu, 01 Aug 2024 12:21:45 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"],"x-message-id":["66ab7dd9cdde5c03b77e1432"]},"statusCode":202},"50ed637b263854bc74bee8aaecd31258246e6a23":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fdaa6cc12fd66-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Wed, 07 Sep 2022 13:40:04 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-message-id":["63189f3455817566900b378c"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["116"]},"statusCode":202},"131edff4e931fea86e4a62aef6aefd19e9f14d7a":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"content-type":["text/html; charset\u003dUTF-8"],"x-message-id":["test-attachment-email-message-id"]},"statusCode":202}}
\ No newline at end of file
+{"872ed332468f4b2427c07accf4e75f1353d64c4d":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca303f6738c9-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Thu, 01 Aug 2024 12:21:45 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"],"x-message-id":["66ab7dd9cdde5c03b77e1432"]},"statusCode":202},"af01f81b08e40fbba382dc8ce7dcd0254a36d595":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f6782e6193cc640-LIS"],"content-type":["application/json"],"date":["Mon, 04 May 2026 12:29:30 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["25"]},"statusCode":401},"50ed637b263854bc74bee8aaecd31258246e6a23":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fdaa6cc12fd66-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Wed, 07 Sep 2022 13:40:04 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-message-id":["63189f3455817566900b378c"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["116"]},"statusCode":202},"131edff4e931fea86e4a62aef6aefd19e9f14d7a":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"content-type":["text/html; charset\u003dUTF-8"],"x-message-id":["test-attachment-email-message-id"]},"statusCode":202}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_TestInvalidPersonalization().json b/src/test/resources/fixtures/EmailSendTest_TestInvalidPersonalization().json
index 7ac61d8..438a210 100644
--- a/src/test/resources/fixtures/EmailSendTest_TestInvalidPersonalization().json
+++ b/src/test/resources/fixtures/EmailSendTest_TestInvalidPersonalization().json
@@ -1 +1 @@
-{"743ef742f69454cd1b3111206cdf5028be8037da":{"body":"{\"message\":\"The personalization.0.data contains array keys with dot notation: invalid.pers2, invalid.pers1\",\"errors\":{\"personalization.0.data\":[\"The personalization.0.data contains array keys with dot notation: invalid.pers2, invalid.pers1\"]}}","headers":{":status":["422"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca37fa346f5b-ATH"],"content-type":["application/json"],"date":["Thu, 01 Aug 2024 12:21:47 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"]},"statusCode":422},"8f2462980d8b8035a1db1929eaa80ea4e958a9b9":{"body":"{\"message\":\"The given data was invalid.\",\"errors\":{\"personalization.0.data\":[\"The personalization.0.data contains array keys with dot notation: invalid.pers2, invalid.pers1\"]}}","headers":{":status":["422"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fda0b0bc86f41-ATH"],"content-type":["application/json"],"date":["Wed, 07 Sep 2022 13:39:39 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["118"]},"statusCode":422}}
\ No newline at end of file
+{"743ef742f69454cd1b3111206cdf5028be8037da":{"body":"{\"message\":\"The personalization.0.data contains array keys with dot notation: invalid.pers2, invalid.pers1\",\"errors\":{\"personalization.0.data\":[\"The personalization.0.data contains array keys with dot notation: invalid.pers2, invalid.pers1\"]}}","headers":{":status":["422"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca37fa346f5b-ATH"],"content-type":["application/json"],"date":["Thu, 01 Aug 2024 12:21:47 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"]},"statusCode":422},"8f2462980d8b8035a1db1929eaa80ea4e958a9b9":{"body":"{\"message\":\"The given data was invalid.\",\"errors\":{\"personalization.0.data\":[\"The personalization.0.data contains array keys with dot notation: invalid.pers2, invalid.pers1\"]}}","headers":{":status":["422"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fda0b0bc86f41-ATH"],"content-type":["application/json"],"date":["Wed, 07 Sep 2022 13:39:39 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["118"]},"statusCode":422},"8064edef0dc9deb16cdedb03286a018f6869f4fd":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f6782ea584f750d-LIS"],"content-type":["application/json"],"date":["Mon, 04 May 2026 12:29:30 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["30"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_TestInvalidTokenFailsWith401().json b/src/test/resources/fixtures/EmailSendTest_TestInvalidTokenFailsWith401().json
index 15017cc..2769780 100644
--- a/src/test/resources/fixtures/EmailSendTest_TestInvalidTokenFailsWith401().json
+++ b/src/test/resources/fixtures/EmailSendTest_TestInvalidTokenFailsWith401().json
@@ -1 +1 @@
-{"10a3065757d7356252bd3438f1f5cb8df6d0fea5":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fdaadbade38d6-ATH"],"content-type":["application/json"],"date":["Wed, 07 Sep 2022 13:40:05 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["119"]},"statusCode":401},"1a5ab7aa0d32d5b2ef7c1db6499d5231378569b8":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca348a31eee8-ATH"],"content-type":["application/json"],"date":["Thu, 01 Aug 2024 12:21:46 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["119"]},"statusCode":401}}
\ No newline at end of file
+{"10a3065757d7356252bd3438f1f5cb8df6d0fea5":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fdaadbade38d6-ATH"],"content-type":["application/json"],"date":["Wed, 07 Sep 2022 13:40:05 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["119"]},"statusCode":401},"1a5ab7aa0d32d5b2ef7c1db6499d5231378569b8":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca348a31eee8-ATH"],"content-type":["application/json"],"date":["Thu, 01 Aug 2024 12:21:46 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["119"]},"statusCode":401},"849fe8da6a9d524084324dc64302994316abcb34":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f6782e7fa1c5b1a-LIS"],"content-type":["application/json"],"date":["Mon, 04 May 2026 12:29:30 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["27"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_TestPojoPersonalization().json b/src/test/resources/fixtures/EmailSendTest_TestPojoPersonalization().json
index 1c64f71..3e8ff09 100644
--- a/src/test/resources/fixtures/EmailSendTest_TestPojoPersonalization().json
+++ b/src/test/resources/fixtures/EmailSendTest_TestPojoPersonalization().json
@@ -1 +1 @@
-{"aecc64b317fd47d52c358aa286b258f46daa7121":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca2aa8e7717c-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Thu, 01 Aug 2024 12:21:45 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"],"x-message-id":["66ab7dd8141c1143f94c890e"]},"statusCode":202},"2f775788bba2e00bbec80a42fc8a02085ba438b3":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fd939c86c6f67-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Wed, 07 Sep 2022 13:39:06 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-message-id":["63189efa179486c438064c02"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["119"]},"statusCode":202}}
\ No newline at end of file
+{"aecc64b317fd47d52c358aa286b258f46daa7121":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca2aa8e7717c-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Thu, 01 Aug 2024 12:21:45 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"],"x-message-id":["66ab7dd8141c1143f94c890e"]},"statusCode":202},"4c752d4be48ac897b132f6860b131d7ce4e82804":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f6782e45b0e48a6-LIS"],"content-type":["application/json"],"date":["Mon, 04 May 2026 12:29:29 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["28"]},"statusCode":401},"2f775788bba2e00bbec80a42fc8a02085ba438b3":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fd939c86c6f67-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Wed, 07 Sep 2022 13:39:06 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-message-id":["63189efa179486c438064c02"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["119"]},"statusCode":202}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_TestSendBulkEmail().json b/src/test/resources/fixtures/EmailSendTest_TestSendBulkEmail().json
index 8bab885..297d52f 100644
--- a/src/test/resources/fixtures/EmailSendTest_TestSendBulkEmail().json
+++ b/src/test/resources/fixtures/EmailSendTest_TestSendBulkEmail().json
@@ -1 +1 @@
-{"4608d385c6f46ad4f9fbb8bc08f9d1e71e0faea0":{"body":"{\"message\":\"The bulk email is being processed.\",\"bulk_email_id\":\"66ab7dd9ef2d2c1378eec1a5\"}","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca2d5ec66f55-ATH"],"content-type":["application/json"],"date":["Thu, 01 Aug 2024 12:21:45 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"]},"statusCode":202},"8bea544a494d82e7caa837ef07dc6ae54aaa8e5a":{"body":"{\"message\":\"The bulk email is being processed.\",\"bulk_email_id\":\"63189f3449a62b6d830a00ff\"}","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fdaa3cf196f6e-ATH"],"content-type":["application/json"],"date":["Wed, 07 Sep 2022 13:40:04 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-ratelimit-limit":["10"],"x-ratelimit-remaining":["8"]},"statusCode":202}}
\ No newline at end of file
+{"4773373f97ed04a6030f29a7d895bcca9262847e":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f6782e53aa562e8-LIS"],"content-type":["application/json"],"date":["Mon, 04 May 2026 12:29:29 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["25"]},"statusCode":401},"4608d385c6f46ad4f9fbb8bc08f9d1e71e0faea0":{"body":"{\"message\":\"The bulk email is being processed.\",\"bulk_email_id\":\"66ab7dd9ef2d2c1378eec1a5\"}","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca2d5ec66f55-ATH"],"content-type":["application/json"],"date":["Thu, 01 Aug 2024 12:21:45 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"]},"statusCode":202},"8bea544a494d82e7caa837ef07dc6ae54aaa8e5a":{"body":"{\"message\":\"The bulk email is being processed.\",\"bulk_email_id\":\"63189f3449a62b6d830a00ff\"}","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fdaa3cf196f6e-ATH"],"content-type":["application/json"],"date":["Wed, 07 Sep 2022 13:40:04 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-ratelimit-limit":["10"],"x-ratelimit-remaining":["8"]},"statusCode":202}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_TestSimpleSend().json b/src/test/resources/fixtures/EmailSendTest_TestSimpleSend().json
index 4069716..2bd8437 100644
--- a/src/test/resources/fixtures/EmailSendTest_TestSimpleSend().json
+++ b/src/test/resources/fixtures/EmailSendTest_TestSimpleSend().json
@@ -1 +1 @@
-{"fae23397116fce941dad41106e3356ac6502a7a5":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fda50c9af6f73-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Wed, 07 Sep 2022 13:39:50 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-message-id":["63189f260a946e37f800f018"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["117"]},"statusCode":202},"c77fa05d778da4eaa4ce70abf8b47cce57cc59ca":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca3b7a7dee8b-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Thu, 01 Aug 2024 12:21:47 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"],"x-message-id":["66ab7ddb3d02e0f1d3a506d8"]},"statusCode":202}}
\ No newline at end of file
+{"fae23397116fce941dad41106e3356ac6502a7a5":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["746fda50c9af6f73-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Wed, 07 Sep 2022 13:39:50 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-09-08T00:00:00Z"],"x-message-id":["63189f260a946e37f800f018"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["117"]},"statusCode":202},"6ba915d00ce334bcb9ad49b7acba19a845a9bd64":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f6782ec2a67055d-LIS"],"content-type":["application/json"],"date":["Mon, 04 May 2026 12:29:30 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["29"]},"statusCode":401},"c77fa05d778da4eaa4ce70abf8b47cce57cc59ca":{"body":"","headers":{":status":["202"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["8ac5ca3b7a7dee8b-ATH"],"content-type":["text/html; charset\u003dUTF-8"],"date":["Thu, 01 Aug 2024 12:21:47 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d31536000; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2024-08-02T00:00:00Z"],"x-message-id":["66ab7ddb3d02e0f1d3a506d8"]},"statusCode":202}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_missing body.json b/src/test/resources/fixtures/EmailSendTest_missing body.json
new file mode 100644
index 0000000..8da57ab
--- /dev/null
+++ b/src/test/resources/fixtures/EmailSendTest_missing body.json
@@ -0,0 +1 @@
+{"8346b720b117bb750c79c5cccee220790ef994f2":{"body":"{\"message\":\"The given data was invalid.\",\"errors\":{\"html\":[\"The html field is required when text is not present.\"],\"text\":[\"The text field is required when html is not present.\"]}}","headers":{":status":["422"],"content-type":["application/json"]},"statusCode":422}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_missing from.json b/src/test/resources/fixtures/EmailSendTest_missing from.json
new file mode 100644
index 0000000..0fea322
--- /dev/null
+++ b/src/test/resources/fixtures/EmailSendTest_missing from.json
@@ -0,0 +1 @@
+{"0f7201b42e59b5a6e50c7a9f05fb162d214ef086":{"body":"{\"message\":\"The given data was invalid.\",\"errors\":{\"from\":[\"The from field is required.\"]}}","headers":{":status":["422"],"content-type":["application/json"]},"statusCode":422}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_missing subject.json b/src/test/resources/fixtures/EmailSendTest_missing subject.json
new file mode 100644
index 0000000..7f9dc78
--- /dev/null
+++ b/src/test/resources/fixtures/EmailSendTest_missing subject.json
@@ -0,0 +1 @@
+{"3dc04f05f61d12eab182502093173ab03f6e4b79":{"body":"{\"message\":\"The given data was invalid.\",\"errors\":{\"subject\":[\"The subject field is required.\"]}}","headers":{":status":["422"],"content-type":["application/json"]},"statusCode":422}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_missing to.json b/src/test/resources/fixtures/EmailSendTest_missing to.json
new file mode 100644
index 0000000..cc6d384
--- /dev/null
+++ b/src/test/resources/fixtures/EmailSendTest_missing to.json
@@ -0,0 +1 @@
+{"acb896bc5d015870fc7fb187ee64412887a033b0":{"body":"{\"message\":\"The given data was invalid.\",\"errors\":{\"to\":[\"The to field is required.\"]}}","headers":{":status":["422"],"content-type":["application/json"]},"statusCode":422}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_testBulkSendStatusHasAllFields().json b/src/test/resources/fixtures/EmailSendTest_testBulkSendStatusHasAllFields().json
new file mode 100644
index 0000000..c65d114
--- /dev/null
+++ b/src/test/resources/fixtures/EmailSendTest_testBulkSendStatusHasAllFields().json
@@ -0,0 +1 @@
+{"63bd823e896c67fed67b64075012bb83f8cf8e7d":{"body":"{\"data\":{\"id\":\"known-bulk-send-id\",\"state\":\"queued\",\"total_recipients_count\":2,\"suppressed_recipients_count\":0,\"suppressed_recipients\":null,\"validation_errors_count\":0,\"validation_errors\":{},\"messages_id\":null,\"created_at\":\"2025-01-10T08:00:00.000000Z\",\"updated_at\":\"2025-01-10T08:01:00.000000Z\"}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["55"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_testSendEmailWithHeaders().json b/src/test/resources/fixtures/EmailSendTest_testSendEmailWithHeaders().json
new file mode 100644
index 0000000..e46e2b4
--- /dev/null
+++ b/src/test/resources/fixtures/EmailSendTest_testSendEmailWithHeaders().json
@@ -0,0 +1 @@
+{"f2294285f9fcd9f1512873ff3fbb04732358da0f":{"body":"","headers":{":status":["202"],"content-type":["text/html; charset=UTF-8"],"x-message-id":["test-message-id-headers"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["115"]},"statusCode":202}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_testSendEmailWithListUnsubscribe().json b/src/test/resources/fixtures/EmailSendTest_testSendEmailWithListUnsubscribe().json
new file mode 100644
index 0000000..8f90207
--- /dev/null
+++ b/src/test/resources/fixtures/EmailSendTest_testSendEmailWithListUnsubscribe().json
@@ -0,0 +1 @@
+{"9b86740adcd358601b386d0876eb4e27d63ddf8c":{"body":"","headers":{":status":["202"],"content-type":["text/html; charset=UTF-8"],"x-message-id":["test-message-id-unsubscribe"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["113"]},"statusCode":202}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_testSendEmailWithPrecedenceBulk().json b/src/test/resources/fixtures/EmailSendTest_testSendEmailWithPrecedenceBulk().json
new file mode 100644
index 0000000..b655fce
--- /dev/null
+++ b/src/test/resources/fixtures/EmailSendTest_testSendEmailWithPrecedenceBulk().json
@@ -0,0 +1 @@
+{"8b868ad50feda2b8204f4191b94eded5673bc718":{"body":"","headers":{":status":["202"],"content-type":["text/html; charset=UTF-8"],"x-message-id":["test-message-id-precedence"],"x-ratelimit-limit":["120"],"x-ratelimit-remaining":["114"]},"statusCode":202}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_testSendEmailWithoutBodyFails().json b/src/test/resources/fixtures/EmailSendTest_testSendEmailWithoutBodyFails().json
new file mode 100644
index 0000000..8da57ab
--- /dev/null
+++ b/src/test/resources/fixtures/EmailSendTest_testSendEmailWithoutBodyFails().json
@@ -0,0 +1 @@
+{"8346b720b117bb750c79c5cccee220790ef994f2":{"body":"{\"message\":\"The given data was invalid.\",\"errors\":{\"html\":[\"The html field is required when text is not present.\"],\"text\":[\"The text field is required when html is not present.\"]}}","headers":{":status":["422"],"content-type":["application/json"]},"statusCode":422}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_testSendEmailWithoutFromFails().json b/src/test/resources/fixtures/EmailSendTest_testSendEmailWithoutFromFails().json
new file mode 100644
index 0000000..0fea322
--- /dev/null
+++ b/src/test/resources/fixtures/EmailSendTest_testSendEmailWithoutFromFails().json
@@ -0,0 +1 @@
+{"0f7201b42e59b5a6e50c7a9f05fb162d214ef086":{"body":"{\"message\":\"The given data was invalid.\",\"errors\":{\"from\":[\"The from field is required.\"]}}","headers":{":status":["422"],"content-type":["application/json"]},"statusCode":422}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_testSendEmailWithoutSubjectFails().json b/src/test/resources/fixtures/EmailSendTest_testSendEmailWithoutSubjectFails().json
new file mode 100644
index 0000000..7f9dc78
--- /dev/null
+++ b/src/test/resources/fixtures/EmailSendTest_testSendEmailWithoutSubjectFails().json
@@ -0,0 +1 @@
+{"3dc04f05f61d12eab182502093173ab03f6e4b79":{"body":"{\"message\":\"The given data was invalid.\",\"errors\":{\"subject\":[\"The subject field is required.\"]}}","headers":{":status":["422"],"content-type":["application/json"]},"statusCode":422}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailSendTest_testSendEmailWithoutToFails().json b/src/test/resources/fixtures/EmailSendTest_testSendEmailWithoutToFails().json
new file mode 100644
index 0000000..cc6d384
--- /dev/null
+++ b/src/test/resources/fixtures/EmailSendTest_testSendEmailWithoutToFails().json
@@ -0,0 +1 @@
+{"acb896bc5d015870fc7fb187ee64412887a033b0":{"body":"{\"message\":\"The given data was invalid.\",\"errors\":{\"to\":[\"The to field is required.\"]}}","headers":{":status":["422"],"content-type":["application/json"]},"statusCode":422}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailVerificationTests_GetListResultsTest().json b/src/test/resources/fixtures/EmailVerificationTests_GetListResultsTest().json
index 1b9ac76..0262c21 100644
--- a/src/test/resources/fixtures/EmailVerificationTests_GetListResultsTest().json
+++ b/src/test/resources/fixtures/EmailVerificationTests_GetListResultsTest().json
@@ -1 +1 @@
-{"9b7a8861a6aefcc9e10a69b8dbe77eb4b1e74449":{"body":"{\"data\":[{\"address\":\"info1@example.com\",\"result\":\"mailbox_not_found\"},{\"address\":\"info2@example.com\",\"result\":\"mailbox_not_found\"},{\"address\":\"info@example.com\",\"result\":\"mailbox_not_found\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/email-verification\\/7z3m5jgroogdpyo6\\/results?1\u003d1\",\"last\":null,\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/email-verification\\/7z3m5jgroogdpyo6\\/results\",\"per_page\":25,\"to\":3}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73db409a2b7938cc-ATH"],"content-type":["application/json"],"date":["Sat, 20 Aug 2022 12:50:02 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-21T00:00:00Z"]},"statusCode":200}}
\ No newline at end of file
+{"9b7a8861a6aefcc9e10a69b8dbe77eb4b1e74449":{"body":"{\"data\":[{\"address\":\"info1@example.com\",\"result\":\"mailbox_not_found\"},{\"address\":\"info2@example.com\",\"result\":\"mailbox_not_found\"},{\"address\":\"info@example.com\",\"result\":\"mailbox_not_found\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/email-verification\\/7z3m5jgroogdpyo6\\/results?1\u003d1\",\"last\":null,\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/email-verification\\/7z3m5jgroogdpyo6\\/results\",\"per_page\":25,\"to\":3}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73db409a2b7938cc-ATH"],"content-type":["application/json"],"date":["Sat, 20 Aug 2022 12:50:02 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-21T00:00:00Z"]},"statusCode":200},"336ca8a7ec2304b5f06287c85ffe0c38337a7680":{"body":"{\"data\":[{\"address\":\"info1@example.com\",\"result\":\"mailbox_not_found\"},{\"address\":\"info2@example.com\",\"result\":\"mailbox_not_found\"},{\"address\":\"info@example.com\",\"result\":\"mailbox_not_found\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/email-verification\\/7z3m5jgroogdpyo6\\/results?page\u003d1\u0026limit\u003d25\",\"last\":null,\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/email-verification\\/7z3m5jgroogdpyo6\\/results\",\"per_page\":25,\"to\":3}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"content-type":["application/json"],"date":["Sat, 20 Aug 2022 12:50:02 GMT"],"server":["cloudflare"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailVerificationTests_testGetVerifyEmailAsyncStatusReturnsResponseFields().json b/src/test/resources/fixtures/EmailVerificationTests_testGetVerifyEmailAsyncStatusReturnsResponseFields().json
new file mode 100644
index 0000000..b1aa796
--- /dev/null
+++ b/src/test/resources/fixtures/EmailVerificationTests_testGetVerifyEmailAsyncStatusReturnsResponseFields().json
@@ -0,0 +1 @@
+{"6c2759d5090a762f831ed4df316104511bbaa974":{"body":"{\"id\":\"abc123asyncstatusid\",\"address\":\"test@example.com\",\"status\":\"completed\",\"result\":\"unknown\",\"error\":null}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailVerificationTests_testGetVerifyEmailAsyncStatusWithEmptyStringThrowsException().json b/src/test/resources/fixtures/EmailVerificationTests_testGetVerifyEmailAsyncStatusWithEmptyStringThrowsException().json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/src/test/resources/fixtures/EmailVerificationTests_testGetVerifyEmailAsyncStatusWithEmptyStringThrowsException().json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailVerificationTests_testGetVerifyEmailAsyncStatusWithInvalidIdThrows404().json b/src/test/resources/fixtures/EmailVerificationTests_testGetVerifyEmailAsyncStatusWithInvalidIdThrows404().json
new file mode 100644
index 0000000..dd0e50b
--- /dev/null
+++ b/src/test/resources/fixtures/EmailVerificationTests_testGetVerifyEmailAsyncStatusWithInvalidIdThrows404().json
@@ -0,0 +1 @@
+{"94defaccd2a4389feae4cb44ee55f214af632408":{"body":"{\"message\":\"Resource not found.\"}","headers":{":status":["404"],"content-type":["application/json"]},"statusCode":404}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailVerificationTests_testGetVerifyEmailAsyncStatusWithNullThrowsException().json b/src/test/resources/fixtures/EmailVerificationTests_testGetVerifyEmailAsyncStatusWithNullThrowsException().json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/src/test/resources/fixtures/EmailVerificationTests_testGetVerifyEmailAsyncStatusWithNullThrowsException().json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailAsyncReturnsResponseFields().json b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailAsyncReturnsResponseFields().json
new file mode 100644
index 0000000..76b3e83
--- /dev/null
+++ b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailAsyncReturnsResponseFields().json
@@ -0,0 +1 @@
+{"8b07d899a976936825de278007ef8a1f6a2fd1e1":{"body":"{\"id\":\"67c83bf24a5d02568029ee10\",\"address\":\"test@example.com\",\"status\":\"queued\",\"result\":null,\"error\":null}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailAsyncWithEmptyStringThrowsException().json b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailAsyncWithEmptyStringThrowsException().json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailAsyncWithEmptyStringThrowsException().json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailAsyncWithInvalidTokenThrows401().json b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailAsyncWithInvalidTokenThrows401().json
new file mode 100644
index 0000000..99d917e
--- /dev/null
+++ b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailAsyncWithInvalidTokenThrows401().json
@@ -0,0 +1 @@
+{"8b07d899a976936825de278007ef8a1f6a2fd1e1":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"content-type":["application/json"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailAsyncWithNullThrowsException().json b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailAsyncWithNullThrowsException().json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailAsyncWithNullThrowsException().json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailReturnsStatus().json b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailReturnsStatus().json
new file mode 100644
index 0000000..7bfc51c
--- /dev/null
+++ b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailReturnsStatus().json
@@ -0,0 +1 @@
+{"1312ba073ddce9807916480f10c041e2da146b86":{"body":"{\"status\":\"valid\"}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailWithEmptyStringThrowsException().json b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailWithEmptyStringThrowsException().json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailWithEmptyStringThrowsException().json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailWithInvalidTokenThrows401().json b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailWithInvalidTokenThrows401().json
new file mode 100644
index 0000000..18e3ba1
--- /dev/null
+++ b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailWithInvalidTokenThrows401().json
@@ -0,0 +1 @@
+{"1312ba073ddce9807916480f10c041e2da146b86":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"content-type":["application/json"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailWithNullThrowsException().json b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailWithNullThrowsException().json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/src/test/resources/fixtures/EmailVerificationTests_testVerifyEmailWithNullThrowsException().json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_catch_all_is_valid.json b/src/test/resources/fixtures/InboundRoutesTest_catch_all_is_valid.json
new file mode 100644
index 0000000..cb6ae80
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_catch_all_is_valid.json
@@ -0,0 +1 @@
+{"9e9f268220815fa869d04046f6d650c97aaa4673":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4f50fa2e3bd-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:04 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["28"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_catch_filter_5_items_is_at_the_limit_and_valid().json b/src/test/resources/fixtures/InboundRoutesTest_catch_filter_5_items_is_at_the_limit_and_valid().json
new file mode 100644
index 0000000..1ed0454
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_catch_filter_5_items_is_at_the_limit_and_valid().json
@@ -0,0 +1 @@
+{"cb68bbad64fabdf545d01d93c5a7a10fc2730099":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4f7acd6b275-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:04 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["29"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_catch_recipient_is_valid.json b/src/test/resources/fixtures/InboundRoutesTest_catch_recipient_is_valid.json
new file mode 100644
index 0000000..ee38845
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_catch_recipient_is_valid.json
@@ -0,0 +1 @@
+{"fd766148980b87c2fdffde8de4aedc40220d04b7":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4f5db4ff53d-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:04 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["30"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_catch_type_all.json b/src/test/resources/fixtures/InboundRoutesTest_catch_type_all.json
new file mode 100644
index 0000000..62b2679
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_catch_type_all.json
@@ -0,0 +1 @@
+{"5d5ffc8fc467e615f50e1b75448500ed4c784542":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4f37b11c156-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:04 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["22"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_catch_type_one.json b/src/test/resources/fixtures/InboundRoutesTest_catch_type_one.json
new file mode 100644
index 0000000..de09dda
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_catch_type_one.json
@@ -0,0 +1 @@
+{"48adfc840e5777981f32a4792459ea202bc03f54":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4f42fb6a10f-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:04 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["32"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_comparer_contains.json b/src/test/resources/fixtures/InboundRoutesTest_comparer_contains.json
new file mode 100644
index 0000000..beebc42
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_comparer_contains.json
@@ -0,0 +1 @@
+{"419d5ae328f69a816e44d36fadb60ec1ec9e84cb":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4e93be848a7-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:02 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["32"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_comparer_ends_with.json b/src/test/resources/fixtures/InboundRoutesTest_comparer_ends_with.json
new file mode 100644
index 0000000..91e8aec
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_comparer_ends_with.json
@@ -0,0 +1 @@
+{"1dbf3ef1562c9eaf6fec0d30eff8b4657634054c":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4ec5d8131f1-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:03 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["28"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_comparer_equal.json b/src/test/resources/fixtures/InboundRoutesTest_comparer_equal.json
new file mode 100644
index 0000000..4ff6f82
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_comparer_equal.json
@@ -0,0 +1 @@
+{"cfdbb75387d5e952bed6f660cde87674fc78656d":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4e75ec294ad-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:02 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["26"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_comparer_not_contains.json b/src/test/resources/fixtures/InboundRoutesTest_comparer_not_contains.json
new file mode 100644
index 0000000..e9b5976
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_comparer_not_contains.json
@@ -0,0 +1 @@
+{"8d85ff1ba4ae2a66906b988795a982171b322d7d":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4ea4f307859-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:02 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["34"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_comparer_not_ends_with.json b/src/test/resources/fixtures/InboundRoutesTest_comparer_not_ends_with.json
new file mode 100644
index 0000000..5588e59
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_comparer_not_ends_with.json
@@ -0,0 +1 @@
+{"476060bf6c24cfcddfa4dc530ff8d5a674ac7a45":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4ee0cdce6de-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:03 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["28"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_comparer_not_equal.json b/src/test/resources/fixtures/InboundRoutesTest_comparer_not_equal.json
new file mode 100644
index 0000000..096eea0
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_comparer_not_equal.json
@@ -0,0 +1 @@
+{"bd644dd0b184076b4a0fd021db3cb79b24ab7b1d":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4e86a9e5816-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:02 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["29"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_comparer_not_starts_with.json b/src/test/resources/fixtures/InboundRoutesTest_comparer_not_starts_with.json
new file mode 100644
index 0000000..3d6f05f
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_comparer_not_starts_with.json
@@ -0,0 +1 @@
+{"cecf1fcf6a5c8c02be5b7bf3c56f8bc8068a975a":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4ed2de2c640-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:03 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["31"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_comparer_starts_with.json b/src/test/resources/fixtures/InboundRoutesTest_comparer_starts_with.json
new file mode 100644
index 0000000..43c1370
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_comparer_starts_with.json
@@ -0,0 +1 @@
+{"b2189dbf9f41d402211ae486200a9652e9902339":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4eb5ca24842-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:02 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["40"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_inbound_domain_not_required_when_domain_enabled_is_false().json b/src/test/resources/fixtures/InboundRoutesTest_inbound_domain_not_required_when_domain_enabled_is_false().json
new file mode 100644
index 0000000..2408b87
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_inbound_domain_not_required_when_domain_enabled_is_false().json
@@ -0,0 +1 @@
+{"ad464b3b9851abf34d634bda2b845511b51fad7e":{"body":"{\"data\":{\"id\":\"jpr9084z9xlw63dn\",\"name\":\"Test inbound name\",\"address\":\"emcbcwyz41fdrr7uuiz1@inbound.mailersend.net\",\"domain\":null,\"dns_checked_at\":null,\"enabled\":true,\"filters\":[{\"type\":\"match_all\",\"key\":null,\"comparer\":null,\"value\":null}],\"forwards\":[],\"mxValues\":{\"priority\":\"10\",\"target\":\"inbound.mailersend.net\"}}}","headers":{":status":["201"],"cache-control":["no-cache, private"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 14:49:26 GMT"],"server":["cloudflare"]},"statusCode":201}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_inbound_domain_supplied_with_domain_enabled_true_passes_validation().json b/src/test/resources/fixtures/InboundRoutesTest_inbound_domain_supplied_with_domain_enabled_true_passes_validation().json
new file mode 100644
index 0000000..195d8cd
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_inbound_domain_supplied_with_domain_enabled_true_passes_validation().json
@@ -0,0 +1 @@
+{"2b8001b93b6670ba65618a73b2afec57f9145376":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4f6cdd8e3cd-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:04 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["32"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_inbound_priority_boundary_values_are_valid().json b/src/test/resources/fixtures/InboundRoutesTest_inbound_priority_boundary_values_are_valid().json
new file mode 100644
index 0000000..378d6ad
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_inbound_priority_boundary_values_are_valid().json
@@ -0,0 +1 @@
+{"b7342e370568951e6a016eb2714b482bd2d8a69a":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4f159194898-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:03 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["38"]},"statusCode":401},"ad464b3b9851abf34d634bda2b845511b51fad7e":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4f00f574898-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:03 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["29"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_match_filter_key_not_required_when_type_is_not_match_header().json b/src/test/resources/fixtures/InboundRoutesTest_match_filter_key_not_required_when_type_is_not_match_header().json
new file mode 100644
index 0000000..0495869
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_match_filter_key_not_required_when_type_is_not_match_header().json
@@ -0,0 +1 @@
+{"6d09792e6c41a6526a97d814b2bfacffbe377b39":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4f87d29f53d-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:04 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["27"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/InboundRoutesTest_match_filter_key_supplied_with_match_header_passes_validation().json b/src/test/resources/fixtures/InboundRoutesTest_match_filter_key_supplied_with_match_header_passes_validation().json
new file mode 100644
index 0000000..d321867
--- /dev/null
+++ b/src/test/resources/fixtures/InboundRoutesTest_match_filter_key_supplied_with_match_header_passes_validation().json
@@ -0,0 +1 @@
+{"d13fa3c550d07081df7e38ee4348812e57dceb00":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f9ff4f28889a10f-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 08:54:04 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["30"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/RecpientsSuppressionListsTest_TestDeleteFromSuppressionList().json b/src/test/resources/fixtures/RecpientsSuppressionListsTest_TestDeleteFromSuppressionList().json
index d4e283a..87aa189 100644
--- a/src/test/resources/fixtures/RecpientsSuppressionListsTest_TestDeleteFromSuppressionList().json
+++ b/src/test/resources/fixtures/RecpientsSuppressionListsTest_TestDeleteFromSuppressionList().json
@@ -1 +1 @@
-{"2e305936b659ecaed00db4eee9208a9a5c16150e":{"body":"{\"data\":[{\"id\":\"633d2c9804b25be53b0b5e28\",\"type\":\"pattern\",\"pattern\":\".*@example.com\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-09-14T09:54:40.000000Z\"},\"created_at\":\"2022-10-05T07:04:56.439000Z\",\"updated_at\":\"2022-10-05T07:04:56.439000Z\"},{\"id\":\"6321a890c51d2696140181ec\",\"type\":\"pattern\",\"pattern\":\".*@example.com\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-09-14T09:54:40.000000Z\"},\"created_at\":\"2022-09-14T10:10:24.001000Z\",\"updated_at\":\"2022-09-14T10:10:24.001000Z\"},{\"id\":\"6321a85da2d201fec0079b8a\",\"type\":\"pattern\",\"pattern\":\".*@example.com\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-09-14T09:54:40.000000Z\"},\"created_at\":\"2022-09-14T10:09:33.502000Z\",\"updated_at\":\"2022-09-14T10:09:33.502000Z\"},{\"id\":\"6321a827a713dd489a082543\",\"type\":\"pattern\",\"pattern\":\".*@example.com\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-09-14T09:54:40.000000Z\"},\"created_at\":\"2022-09-14T10:08:39.698000Z\",\"updated_at\":\"2022-09-14T10:08:39.698000Z\"},{\"id\":\"6321a7b8064166fd2d0d0e8d\",\"type\":\"exact\",\"pattern\":\"test@example.com\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-09-14T09:54:40.000000Z\"},\"created_at\":\"2022-09-14T10:06:48.514000Z\",\"updated_at\":\"2022-09-14T10:06:48.514000Z\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist?page\u003d1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist?page\u003d1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[{\"url\":null,\"label\":\"\u0026laquo; Previous\",\"active\":false},{\"url\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist?page\u003d1\",\"label\":\"1\",\"active\":true},{\"url\":null,\"label\":\"Next \u0026raquo;\",\"active\":false}],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist\",\"per_page\":25,\"to\":5,\"total\":5}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["75544e593ff76f56-ATH"],"content-type":["application/json"],"date":["Wed, 05 Oct 2022 07:04:56 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-10-06T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["58"]},"statusCode":200},"ef05ba48e5cb132eb4acb9d9498c60cc85103e94":{"body":"{\"data\":[{\"id\":\"629f8f551701d31cba0cf02f\",\"created_at\":\"2022-06-07T17:48:05.783000Z\",\"recipient\":{\"id\":\"629f8f551424bb29ba0a706e\",\"email\":\"test@example.com\",\"created_at\":\"2022-06-07T17:48:05.474000Z\",\"updated_at\":\"2022-06-07T17:55:48.928000Z\",\"deleted_at\":\"\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-09-14T09:54:40.000000Z\"}}}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints?page\u003d1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints?page\u003d1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[{\"url\":null,\"label\":\"\u0026laquo; Previous\",\"active\":false},{\"url\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints?page\u003d1\",\"label\":\"1\",\"active\":true},{\"url\":null,\"label\":\"Next \u0026raquo;\",\"active\":false}],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints\",\"per_page\":25,\"to\":1,\"total\":1}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["75544e5e9bbd6f56-ATH"],"content-type":["application/json"],"date":["Wed, 05 Oct 2022 07:04:57 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-10-06T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["55"]},"statusCode":200},"e78ca656f7b3129a3cc81189c9617f2499489a25":{"body":"{\"data\":[{\"id\":\"633d2c9804b25be53b0b5e28\",\"type\":\"pattern\",\"pattern\":\".*@example.com\",\"created_at\":\"2022-10-05T07:04:56.439000Z\",\"updated_at\":\"2022-10-05T07:04:56.439000Z\"}]}","headers":{":status":["201"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["75544e576e8e6f56-ATH"],"content-type":["application/json"],"date":["Wed, 05 Oct 2022 07:04:56 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-10-06T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":201},"6b5785f3aad1ca1eb2b60e08c70bc9b17eb022a4":{"body":"[]","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["75544e607ceb6f56-ATH"],"content-type":["application/json"],"date":["Wed, 05 Oct 2022 07:04:57 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-10-06T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["54"]},"statusCode":200},"d22efc0af4e06dd9b59f0ec708fce85d09b42197":{"body":"{\"data\":[{\"id\":\"629f8f551701d31cba0cf02f\",\"created_at\":\"2022-06-07T17:48:05.783000Z\",\"recipient\":{\"id\":\"629f8f551424bb29ba0a706e\",\"email\":\"test@example.com\",\"created_at\":\"2022-06-07T17:48:05.474000Z\",\"updated_at\":\"2022-06-07T17:55:48.928000Z\",\"deleted_at\":\"\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-09-14T09:54:40.000000Z\"}}}]}","headers":{":status":["201"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["75544e5c8a526f56-ATH"],"content-type":["application/json"],"date":["Wed, 05 Oct 2022 07:04:57 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-10-06T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["56"]},"statusCode":201},"b05039bb9750adad3d89a9b9513e0ca149ae9376":{"body":"[]","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["75544e5b59736f56-ATH"],"content-type":["application/json"],"date":["Wed, 05 Oct 2022 07:04:57 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-10-06T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["57"]},"statusCode":200}}
\ No newline at end of file
+{"2e305936b659ecaed00db4eee9208a9a5c16150e":{"body":"{\"data\":[{\"id\":\"633d2c9804b25be53b0b5e28\",\"type\":\"pattern\",\"pattern\":\".*@example.com\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-09-14T09:54:40.000000Z\"},\"created_at\":\"2022-10-05T07:04:56.439000Z\",\"updated_at\":\"2022-10-05T07:04:56.439000Z\"},{\"id\":\"6321a890c51d2696140181ec\",\"type\":\"pattern\",\"pattern\":\".*@example.com\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-09-14T09:54:40.000000Z\"},\"created_at\":\"2022-09-14T10:10:24.001000Z\",\"updated_at\":\"2022-09-14T10:10:24.001000Z\"},{\"id\":\"6321a85da2d201fec0079b8a\",\"type\":\"pattern\",\"pattern\":\".*@example.com\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-09-14T09:54:40.000000Z\"},\"created_at\":\"2022-09-14T10:09:33.502000Z\",\"updated_at\":\"2022-09-14T10:09:33.502000Z\"},{\"id\":\"6321a827a713dd489a082543\",\"type\":\"pattern\",\"pattern\":\".*@example.com\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-09-14T09:54:40.000000Z\"},\"created_at\":\"2022-09-14T10:08:39.698000Z\",\"updated_at\":\"2022-09-14T10:08:39.698000Z\"},{\"id\":\"6321a7b8064166fd2d0d0e8d\",\"type\":\"exact\",\"pattern\":\"test@example.com\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-09-14T09:54:40.000000Z\"},\"created_at\":\"2022-09-14T10:06:48.514000Z\",\"updated_at\":\"2022-09-14T10:06:48.514000Z\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist?page\u003d1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist?page\u003d1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[{\"url\":null,\"label\":\"\u0026laquo; Previous\",\"active\":false},{\"url\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist?page\u003d1\",\"label\":\"1\",\"active\":true},{\"url\":null,\"label\":\"Next \u0026raquo;\",\"active\":false}],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist\",\"per_page\":25,\"to\":5,\"total\":5}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["75544e593ff76f56-ATH"],"content-type":["application/json"],"date":["Wed, 05 Oct 2022 07:04:56 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-10-06T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["58"]},"statusCode":200},"ef05ba48e5cb132eb4acb9d9498c60cc85103e94":{"body":"{\"data\":[{\"id\":\"629f8f551701d31cba0cf02f\",\"created_at\":\"2022-06-07T17:48:05.783000Z\",\"recipient\":{\"id\":\"629f8f551424bb29ba0a706e\",\"email\":\"test@example.com\",\"created_at\":\"2022-06-07T17:48:05.474000Z\",\"updated_at\":\"2022-06-07T17:55:48.928000Z\",\"deleted_at\":\"\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-09-14T09:54:40.000000Z\"}}}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints?page\u003d1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints?page\u003d1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[{\"url\":null,\"label\":\"\u0026laquo; Previous\",\"active\":false},{\"url\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints?page\u003d1\",\"label\":\"1\",\"active\":true},{\"url\":null,\"label\":\"Next \u0026raquo;\",\"active\":false}],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints\",\"per_page\":25,\"to\":1,\"total\":1}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["75544e5e9bbd6f56-ATH"],"content-type":["application/json"],"date":["Wed, 05 Oct 2022 07:04:57 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-10-06T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["55"]},"statusCode":200},"e78ca656f7b3129a3cc81189c9617f2499489a25":{"body":"{\"data\":[{\"id\":\"633d2c9804b25be53b0b5e28\",\"type\":\"pattern\",\"pattern\":\".*@example.com\",\"created_at\":\"2022-10-05T07:04:56.439000Z\",\"updated_at\":\"2022-10-05T07:04:56.439000Z\"}]}","headers":{":status":["201"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["75544e576e8e6f56-ATH"],"content-type":["application/json"],"date":["Wed, 05 Oct 2022 07:04:56 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-10-06T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":201},"6b5785f3aad1ca1eb2b60e08c70bc9b17eb022a4":{"body":"[]","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["75544e607ceb6f56-ATH"],"content-type":["application/json"],"date":["Wed, 05 Oct 2022 07:04:57 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-10-06T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["54"]},"statusCode":200},"8d4982408ce42e102d1b1ea315a6fb8daf458739":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89ab568bb54842-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 15:59:02 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["27"]},"statusCode":401},"d22efc0af4e06dd9b59f0ec708fce85d09b42197":{"body":"{\"data\":[{\"id\":\"629f8f551701d31cba0cf02f\",\"created_at\":\"2022-06-07T17:48:05.783000Z\",\"recipient\":{\"id\":\"629f8f551424bb29ba0a706e\",\"email\":\"test@example.com\",\"created_at\":\"2022-06-07T17:48:05.474000Z\",\"updated_at\":\"2022-06-07T17:55:48.928000Z\",\"deleted_at\":\"\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-09-14T09:54:40.000000Z\"}}}]}","headers":{":status":["201"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["75544e5c8a526f56-ATH"],"content-type":["application/json"],"date":["Wed, 05 Oct 2022 07:04:57 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-10-06T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["56"]},"statusCode":201},"b05039bb9750adad3d89a9b9513e0ca149ae9376":{"body":"[]","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["75544e5b59736f56-ATH"],"content-type":["application/json"],"date":["Wed, 05 Oct 2022 07:04:57 GMT"],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-10-06T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["57"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/RecpientsSuppressionListsTest_TestGetFromSuppressionLists().json b/src/test/resources/fixtures/RecpientsSuppressionListsTest_TestGetFromSuppressionLists().json
index 8fd04ab..e6570ad 100644
--- a/src/test/resources/fixtures/RecpientsSuppressionListsTest_TestGetFromSuppressionLists().json
+++ b/src/test/resources/fixtures/RecpientsSuppressionListsTest_TestGetFromSuppressionLists().json
@@ -1 +1 @@
-{"340d67d87050b8f8b48631246c5def121b95459c":{"body":"{\"data\":[],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/hard-bounces?page\u003d1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/hard-bounces?page\u003d1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":null,\"last_page\":1,\"links\":[{\"url\":null,\"label\":\"\u0026laquo; Previous\",\"active\":false},{\"url\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/hard-bounces?page\u003d1\",\"label\":\"1\",\"active\":true},{\"url\":null,\"label\":\"Next \u0026raquo;\",\"active\":false}],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/hard-bounces\",\"per_page\":25,\"to\":null,\"total\":0}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d33415ba0f6f73-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:23:23 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["54"]},"statusCode":200},"a1d332f09ca4784de3f6dcecd19b59dc9753a3dd":{"body":"{\"data\":[{\"id\":\"629f8f56dd289029750bcc45\",\"reason\":null,\"readable_reason\":null,\"recipient\":{\"id\":\"629f8f551424bb29ba0a706e\",\"email\":\"test@example.com\",\"created_at\":\"2022-06-07T17:48:05.474000Z\",\"updated_at\":\"2022-06-07T17:55:48.928000Z\",\"deleted_at\":\"\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-06-15T11:32:41.000000Z\"}},\"created_at\":\"2022-06-07T17:48:06.089000Z\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/unsubscribes?page\u003d1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/unsubscribes?page\u003d1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[{\"url\":null,\"label\":\"\u0026laquo; Previous\",\"active\":false},{\"url\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/unsubscribes?page\u003d1\",\"label\":\"1\",\"active\":true},{\"url\":null,\"label\":\"Next \u0026raquo;\",\"active\":false}],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/unsubscribes\",\"per_page\":25,\"to\":1,\"total\":1}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d3341bcbfe6f73-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:23:24 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["52"]},"statusCode":200},"6a364e8433c5f16293ff8f293c1e7d290d833592":{"body":"{\"data\":[{\"id\":\"629f8f551701d31cba0cf02f\",\"created_at\":\"2022-06-07T17:48:05.783000Z\",\"recipient\":{\"id\":\"629f8f551424bb29ba0a706e\",\"email\":\"test@example.com\",\"created_at\":\"2022-06-07T17:48:05.474000Z\",\"updated_at\":\"2022-06-07T17:55:48.928000Z\",\"deleted_at\":\"\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-06-15T11:32:41.000000Z\"}}}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints?page\u003d1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints?page\u003d1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[{\"url\":null,\"label\":\"\u0026laquo; Previous\",\"active\":false},{\"url\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints?page\u003d1\",\"label\":\"1\",\"active\":true},{\"url\":null,\"label\":\"Next \u0026raquo;\",\"active\":false}],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints\",\"per_page\":25,\"to\":1,\"total\":1}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d33418cf1d6f73-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:23:24 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["53"]},"statusCode":200},"dd11e33d55ef38bde1911fd0d8b5f14dcc0a84eb":{"body":"{\"data\":[{\"id\":\"62ff8ec78fd9ece450003a99\",\"type\":\"pattern\",\"pattern\":\".*@example.com\",\"domain\":null,\"created_at\":\"2022-08-19T13:23:19.349000Z\",\"updated_at\":\"2022-08-19T13:23:19.349000Z\"},{\"id\":\"62ff8ec78fd9ece450003a98\",\"type\":\"exact\",\"pattern\":\"test@example.com\",\"domain\":null,\"created_at\":\"2022-08-19T13:23:19.345000Z\",\"updated_at\":\"2022-08-19T13:23:19.345000Z\"},{\"id\":\"62ff8ea38ccfe51d8c0df1fa\",\"type\":\"exact\",\"pattern\":\"john@mailerlite.com\",\"domain\":null,\"created_at\":\"2022-08-19T13:22:43.843000Z\",\"updated_at\":\"2022-08-19T13:22:43.843000Z\"},{\"id\":\"62a20de00d3c85856401b4e5\",\"type\":\"exact\",\"pattern\":\"bcc@test-sdk.com\",\"domain\":null,\"created_at\":\"2022-06-09T15:12:32.618000Z\",\"updated_at\":\"2022-06-09T15:12:32.618000Z\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist?page\u003d1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist?page\u003d1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[{\"url\":null,\"label\":\"\u0026laquo; Previous\",\"active\":false},{\"url\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist?page\u003d1\",\"label\":\"1\",\"active\":true},{\"url\":null,\"label\":\"Next \u0026raquo;\",\"active\":false}],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist\",\"per_page\":25,\"to\":4,\"total\":4}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d334118bb06f73-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:23:22 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["55"]},"statusCode":200}}
\ No newline at end of file
+{"340d67d87050b8f8b48631246c5def121b95459c":{"body":"{\"data\":[],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/hard-bounces?page\u003d1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/hard-bounces?page\u003d1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":null,\"last_page\":1,\"links\":[{\"url\":null,\"label\":\"\u0026laquo; Previous\",\"active\":false},{\"url\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/hard-bounces?page\u003d1\",\"label\":\"1\",\"active\":true},{\"url\":null,\"label\":\"Next \u0026raquo;\",\"active\":false}],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/hard-bounces\",\"per_page\":25,\"to\":null,\"total\":0}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d33415ba0f6f73-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:23:23 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["54"]},"statusCode":200},"a1d332f09ca4784de3f6dcecd19b59dc9753a3dd":{"body":"{\"data\":[{\"id\":\"629f8f56dd289029750bcc45\",\"reason\":null,\"readable_reason\":null,\"recipient\":{\"id\":\"629f8f551424bb29ba0a706e\",\"email\":\"test@example.com\",\"created_at\":\"2022-06-07T17:48:05.474000Z\",\"updated_at\":\"2022-06-07T17:55:48.928000Z\",\"deleted_at\":\"\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-06-15T11:32:41.000000Z\"}},\"created_at\":\"2022-06-07T17:48:06.089000Z\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/unsubscribes?page\u003d1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/unsubscribes?page\u003d1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[{\"url\":null,\"label\":\"\u0026laquo; Previous\",\"active\":false},{\"url\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/unsubscribes?page\u003d1\",\"label\":\"1\",\"active\":true},{\"url\":null,\"label\":\"Next \u0026raquo;\",\"active\":false}],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/unsubscribes\",\"per_page\":25,\"to\":1,\"total\":1}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d3341bcbfe6f73-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:23:24 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["52"]},"statusCode":200},"6a364e8433c5f16293ff8f293c1e7d290d833592":{"body":"{\"data\":[{\"id\":\"629f8f551701d31cba0cf02f\",\"created_at\":\"2022-06-07T17:48:05.783000Z\",\"recipient\":{\"id\":\"629f8f551424bb29ba0a706e\",\"email\":\"test@example.com\",\"created_at\":\"2022-06-07T17:48:05.474000Z\",\"updated_at\":\"2022-06-07T17:55:48.928000Z\",\"deleted_at\":\"\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-06-15T11:32:41.000000Z\"}}}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints?page\u003d1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints?page\u003d1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[{\"url\":null,\"label\":\"\u0026laquo; Previous\",\"active\":false},{\"url\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints?page\u003d1\",\"label\":\"1\",\"active\":true},{\"url\":null,\"label\":\"Next \u0026raquo;\",\"active\":false}],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/spam-complaints\",\"per_page\":25,\"to\":1,\"total\":1}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d33418cf1d6f73-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:23:24 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["53"]},"statusCode":200},"755e3662dacc71808e430881d703e0251c8207ca":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9f89ab558ed6e3c0-LIS"],"content-type":["application/json"],"date":["Fri, 08 May 2026 15:59:02 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["34"]},"statusCode":401},"dd11e33d55ef38bde1911fd0d8b5f14dcc0a84eb":{"body":"{\"data\":[{\"id\":\"62ff8ec78fd9ece450003a99\",\"type\":\"pattern\",\"pattern\":\".*@example.com\",\"domain\":null,\"created_at\":\"2022-08-19T13:23:19.349000Z\",\"updated_at\":\"2022-08-19T13:23:19.349000Z\"},{\"id\":\"62ff8ec78fd9ece450003a98\",\"type\":\"exact\",\"pattern\":\"test@example.com\",\"domain\":null,\"created_at\":\"2022-08-19T13:23:19.345000Z\",\"updated_at\":\"2022-08-19T13:23:19.345000Z\"},{\"id\":\"62ff8ea38ccfe51d8c0df1fa\",\"type\":\"exact\",\"pattern\":\"john@mailerlite.com\",\"domain\":null,\"created_at\":\"2022-08-19T13:22:43.843000Z\",\"updated_at\":\"2022-08-19T13:22:43.843000Z\"},{\"id\":\"62a20de00d3c85856401b4e5\",\"type\":\"exact\",\"pattern\":\"bcc@test-sdk.com\",\"domain\":null,\"created_at\":\"2022-06-09T15:12:32.618000Z\",\"updated_at\":\"2022-06-09T15:12:32.618000Z\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist?page\u003d1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist?page\u003d1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[{\"url\":null,\"label\":\"\u0026laquo; Previous\",\"active\":false},{\"url\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist?page\u003d1\",\"label\":\"1\",\"active\":true},{\"url\":null,\"label\":\"Next \u0026raquo;\",\"active\":false}],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/blocklist\",\"per_page\":25,\"to\":4,\"total\":4}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d334118bb06f73-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:23:22 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["55"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteBlocklistAllItems().json b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteBlocklistAllItems().json
new file mode 100644
index 0000000..2aef0e4
--- /dev/null
+++ b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteBlocklistAllItems().json
@@ -0,0 +1 @@
+{"1b4afdcd09a8f30227176f58a243f51187d57c8c":{"body":"[]","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteHardBouncesAllItems().json b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteHardBouncesAllItems().json
new file mode 100644
index 0000000..137b70f
--- /dev/null
+++ b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteHardBouncesAllItems().json
@@ -0,0 +1 @@
+{"38926aaf2f3b9cb9631e31396ccf2a28d0de46ad":{"body":"[]","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteHardBouncesItems().json b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteHardBouncesItems().json
new file mode 100644
index 0000000..eab60a1
--- /dev/null
+++ b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteHardBouncesItems().json
@@ -0,0 +1 @@
+{"546ee015c908e0b6949c9d9158513f1d025a763a":{"body":"{\"data\":[{\"id\":\"629f8f56dd289029750bcc45\",\"reason\":null,\"readable_reason\":null,\"recipient\":{\"id\":\"629f8f551424bb29ba0a706e\",\"email\":\"test@example.com\",\"created_at\":\"2022-06-07T17:48:05.474000Z\",\"updated_at\":\"2022-06-07T17:55:48.928000Z\",\"deleted_at\":\"\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-06-15T11:32:41.000000Z\"}},\"created_at\":\"2022-06-07T17:48:06.089000Z\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/hard-bounces?page=1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/hard-bounces?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/hard-bounces\",\"per_page\":10,\"to\":1,\"total\":1}}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200},"da519a43a584020fe0873e988031a15e265691a1":{"body":"[]","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteOnHoldListAllItems().json b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteOnHoldListAllItems().json
new file mode 100644
index 0000000..023c68c
--- /dev/null
+++ b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteOnHoldListAllItems().json
@@ -0,0 +1 @@
+{"103877d28bc3ce4b127ff935be3c46ba3c5bc958":{"body":"[]","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteOnHoldListItems().json b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteOnHoldListItems().json
new file mode 100644
index 0000000..8201186
--- /dev/null
+++ b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteOnHoldListItems().json
@@ -0,0 +1 @@
+{"24b42400c3c180658a61425f377996806cd50f4d":{"body":"{\"data\":[{\"id\":\"629f8f56dd289029750bcc47\",\"reason\":null,\"readable_reason\":null,\"recipient\":{\"id\":\"629f8f551424bb29ba0a706e\",\"email\":\"test@example.com\",\"created_at\":\"2022-06-07T17:48:05.474000Z\",\"updated_at\":\"2022-06-07T17:55:48.928000Z\",\"deleted_at\":\"\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-06-15T11:32:41.000000Z\"}},\"created_at\":\"2022-06-07T17:48:06.089000Z\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/on-hold-list?page=1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/on-hold-list?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/on-hold-list\",\"per_page\":10,\"to\":1,\"total\":1}}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200},"814672f673159a4147f1915939fdb486ce8f2437":{"body":"[]","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteSpamComplaintsAllItems().json b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteSpamComplaintsAllItems().json
new file mode 100644
index 0000000..3ad1857
--- /dev/null
+++ b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteSpamComplaintsAllItems().json
@@ -0,0 +1 @@
+{"cdd481c05c9afb0f8a39c07e0ec40d54d33b0ce4":{"body":"[]","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteUnsubscribesAllItems().json b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteUnsubscribesAllItems().json
new file mode 100644
index 0000000..87b879b
--- /dev/null
+++ b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteUnsubscribesAllItems().json
@@ -0,0 +1 @@
+{"8c74953ce08fd961168040f99a8f90f49b9bbe80":{"body":"[]","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteUnsubscribesItems().json b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteUnsubscribesItems().json
new file mode 100644
index 0000000..3064c32
--- /dev/null
+++ b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testDeleteUnsubscribesItems().json
@@ -0,0 +1 @@
+{"bb92eec71528a059c3b3bd909f4910dc799522cf":{"body":"{\"data\":[{\"id\":\"629f8f56dd289029750bcc46\",\"reason\":null,\"readable_reason\":null,\"recipient\":{\"id\":\"629f8f551424bb29ba0a706e\",\"email\":\"test@example.com\",\"created_at\":\"2022-06-07T17:48:05.474000Z\",\"updated_at\":\"2022-06-07T17:55:48.928000Z\",\"deleted_at\":\"\",\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2022-04-20T11:36:15.000000Z\",\"updated_at\":\"2022-06-15T11:32:41.000000Z\"}},\"created_at\":\"2022-06-07T17:48:06.089000Z\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/unsubscribes?page=1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/unsubscribes?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/suppressions\\/unsubscribes\",\"per_page\":10,\"to\":1,\"total\":1}}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200},"fcf626bea809926053ba9f862b7ca4c2d5cd89d3":{"body":"[]","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/RecpientsSuppressionListsTest_testGetRecipientsWithPageLimitAndDomainIdParams().json b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testGetRecipientsWithPageLimitAndDomainIdParams().json
new file mode 100644
index 0000000..d60e6d4
--- /dev/null
+++ b/src/test/resources/fixtures/RecpientsSuppressionListsTest_testGetRecipientsWithPageLimitAndDomainIdParams().json
@@ -0,0 +1 @@
+{"77f95e598dfaebb6d746cc5589967a89a4bc4b51":{"body":"{\"data\":[{\"id\":\"629f8f551424bb29ba0a706e\",\"email\":\"test@example.com\",\"created_at\":\"2022-06-07T17:48:05.474000Z\",\"updated_at\":\"2022-06-07T17:55:48.928000Z\",\"deleted_at\":\"\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/recipients?page=1\",\"last\":null,\"prev\":null,\"next\":null},\"meta\":{\"current_page\":2,\"from\":1,\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/recipients\",\"per_page\":10,\"to\":1}}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/ScheduledMessagesTest_testCanDeleteScheduledMessage().json b/src/test/resources/fixtures/ScheduledMessagesTest_testCanDeleteScheduledMessage().json
new file mode 100644
index 0000000..fd1f5b5
--- /dev/null
+++ b/src/test/resources/fixtures/ScheduledMessagesTest_testCanDeleteScheduledMessage().json
@@ -0,0 +1 @@
+{"3d1538e877ebe845eeec6fe455c994663bf642d0":{"body":"","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["56"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/ScheduledMessagesTest_testCanGetScheduledMessages().json b/src/test/resources/fixtures/ScheduledMessagesTest_testCanGetScheduledMessages().json
new file mode 100644
index 0000000..79a604d
--- /dev/null
+++ b/src/test/resources/fixtures/ScheduledMessagesTest_testCanGetScheduledMessages().json
@@ -0,0 +1 @@
+{"2ab10d72811d2a379b71fc69c74ea6b29745b3a4":{"body":"{\"data\":[{\"id\":\"test-schedule-id-123\",\"message_id\":\"test-message-id-456\",\"subject\":\"Test Subject\",\"send_at\":\"2025-01-15T10:00:00.000000Z\",\"status\":\"scheduled\",\"status_message\":null,\"created_at\":\"2025-01-10T08:00:00.000000Z\",\"message\":{\"id\":\"test-message-id-456\",\"created_at\":\"2025-01-10T08:00:00.000000Z\",\"updated_at\":\"2025-01-10T08:00:00.000000Z\"},\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2024-01-01T00:00:00.000000Z\",\"updated_at\":\"2024-01-01T00:00:00.000000Z\"}}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/message-schedules?page=1\",\"last\":null,\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/message-schedules\",\"per_page\":25,\"to\":1}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/ScheduledMessagesTest_testCanGetScheduledMessagesWithFilters().json b/src/test/resources/fixtures/ScheduledMessagesTest_testCanGetScheduledMessagesWithFilters().json
new file mode 100644
index 0000000..a9eabf0
--- /dev/null
+++ b/src/test/resources/fixtures/ScheduledMessagesTest_testCanGetScheduledMessagesWithFilters().json
@@ -0,0 +1 @@
+{"f2e502e9af15a76152753f5cde72c7eded4c59b6":{"body":"{\"data\":[{\"id\":\"test-schedule-id-123\",\"message_id\":\"test-message-id-456\",\"subject\":\"Test Subject\",\"send_at\":\"2025-01-15T10:00:00.000000Z\",\"status\":\"scheduled\",\"status_message\":null,\"created_at\":\"2025-01-10T08:00:00.000000Z\",\"message\":{\"id\":\"test-message-id-456\",\"created_at\":\"2025-01-10T08:00:00.000000Z\",\"updated_at\":\"2025-01-10T08:00:00.000000Z\"},\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2024-01-01T00:00:00.000000Z\",\"updated_at\":\"2024-01-01T00:00:00.000000Z\"}}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/message-schedules?page=2\",\"last\":null,\"prev\":null,\"next\":null},\"meta\":{\"current_page\":2,\"from\":1,\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/message-schedules\",\"per_page\":10,\"to\":1}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["58"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/ScheduledMessagesTest_testCanGetScheduledMessages_with_filters().json b/src/test/resources/fixtures/ScheduledMessagesTest_testCanGetScheduledMessages_with_filters().json
new file mode 100644
index 0000000..20d2a27
--- /dev/null
+++ b/src/test/resources/fixtures/ScheduledMessagesTest_testCanGetScheduledMessages_with_filters().json
@@ -0,0 +1 @@
+{"f2e502e9af15a76152753f5cde72c7eded4c59b6":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa09a53f9e3b17c-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:46:58 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["41"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/ScheduledMessagesTest_testCanGetSingleScheduledMessage().json b/src/test/resources/fixtures/ScheduledMessagesTest_testCanGetSingleScheduledMessage().json
new file mode 100644
index 0000000..b355272
--- /dev/null
+++ b/src/test/resources/fixtures/ScheduledMessagesTest_testCanGetSingleScheduledMessage().json
@@ -0,0 +1 @@
+{"d0584eeda9911e48967b666502f6e1b61181dd0e":{"body":"{\"data\":{\"id\":\"test-schedule-id-123\",\"message_id\":\"test-message-id-456\",\"subject\":\"Test Subject\",\"send_at\":\"2025-01-15T10:00:00.000000Z\",\"status\":\"scheduled\",\"status_message\":null,\"created_at\":\"2025-01-10T08:00:00.000000Z\",\"message\":{\"id\":\"test-message-id-456\",\"created_at\":\"2025-01-10T08:00:00.000000Z\",\"updated_at\":\"2025-01-10T08:00:00.000000Z\"},\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\",\"created_at\":\"2024-01-01T00:00:00.000000Z\",\"updated_at\":\"2024-01-01T00:00:00.000000Z\"}}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["57"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/ScheduledMessagesTest_testDeleteScheduledMessageWithInvalidIdFails().json b/src/test/resources/fixtures/ScheduledMessagesTest_testDeleteScheduledMessageWithInvalidIdFails().json
new file mode 100644
index 0000000..05e8229
--- /dev/null
+++ b/src/test/resources/fixtures/ScheduledMessagesTest_testDeleteScheduledMessageWithInvalidIdFails().json
@@ -0,0 +1 @@
+{"ae83c493638091aa6ebd06571cbe823b59250027":{"body":"{\"message\":\"Not Found\"}","headers":{":status":["404"],"content-type":["application/json"]},"statusCode":404}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/ScheduledMessagesTest_testGetScheduledMessageWithInvalidIdFails().json b/src/test/resources/fixtures/ScheduledMessagesTest_testGetScheduledMessageWithInvalidIdFails().json
new file mode 100644
index 0000000..275999d
--- /dev/null
+++ b/src/test/resources/fixtures/ScheduledMessagesTest_testGetScheduledMessageWithInvalidIdFails().json
@@ -0,0 +1 @@
+{"71cad22729870c40de384558a324d6c92259bcdb":{"body":"{\"message\":\"Not Found\"}","headers":{":status":["404"],"content-type":["application/json"]},"statusCode":404}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/ScheduledMessagesTest_testInvalidTokenFailsWith401OnGetScheduledMessages().json b/src/test/resources/fixtures/ScheduledMessagesTest_testInvalidTokenFailsWith401OnGetScheduledMessages().json
new file mode 100644
index 0000000..a7d8f88
--- /dev/null
+++ b/src/test/resources/fixtures/ScheduledMessagesTest_testInvalidTokenFailsWith401OnGetScheduledMessages().json
@@ -0,0 +1 @@
+{"2ab10d72811d2a379b71fc69c74ea6b29745b3a4":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"content-type":["application/json"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SenderIdentitiesTest_TestCreateIdentity().json b/src/test/resources/fixtures/SenderIdentitiesTest_TestCreateIdentity().json
new file mode 100644
index 0000000..e9fb471
--- /dev/null
+++ b/src/test/resources/fixtures/SenderIdentitiesTest_TestCreateIdentity().json
@@ -0,0 +1 @@
+{"1b730695d71b06e085cf92e9dbeb8e1e51fd3423":{"body":"{\"data\":{\"id\":\"ident-id-456\",\"email\":\"test@example.com\",\"name\":\"Test Identity\",\"reply_to_email\":null,\"reply_to_name\":null,\"is_verified\":false,\"resends\":0,\"add_note\":false,\"personal_note\":null,\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\"}}}","headers":{":status":["201"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":201}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SenderIdentitiesTest_TestDeleteIdentity().json b/src/test/resources/fixtures/SenderIdentitiesTest_TestDeleteIdentity().json
new file mode 100644
index 0000000..0ccb211
--- /dev/null
+++ b/src/test/resources/fixtures/SenderIdentitiesTest_TestDeleteIdentity().json
@@ -0,0 +1 @@
+{"492402b1133f451e25b82023ee203a865be225f7":{"body":"","headers":{":status":["204"],"content-type":["text/html; charset=UTF-8"]},"statusCode":204}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SenderIdentitiesTest_TestDeleteIdentityByEmail().json b/src/test/resources/fixtures/SenderIdentitiesTest_TestDeleteIdentityByEmail().json
new file mode 100644
index 0000000..693a1d9
--- /dev/null
+++ b/src/test/resources/fixtures/SenderIdentitiesTest_TestDeleteIdentityByEmail().json
@@ -0,0 +1 @@
+{"2e6ac0ff4c6396fa76a757de88ce530e4c024332":{"body":"","headers":{":status":["204"],"content-type":["text/html; charset=UTF-8"]},"statusCode":204}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SenderIdentitiesTest_TestGetIdentities().json b/src/test/resources/fixtures/SenderIdentitiesTest_TestGetIdentities().json
new file mode 100644
index 0000000..cd18304
--- /dev/null
+++ b/src/test/resources/fixtures/SenderIdentitiesTest_TestGetIdentities().json
@@ -0,0 +1 @@
+{"17ecddff627c6b4b54df0620ffdc718e820af411":{"body":"{\"data\":[{\"id\":\"ident-id-123\",\"email\":\"test@example.com\",\"name\":\"Test Identity\",\"reply_to_email\":\"reply@example.com\",\"reply_to_name\":\"Reply Name\",\"is_verified\":true,\"resends\":0,\"add_note\":false,\"personal_note\":null,\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\"}}],\"links\":{\"first\":\"https://api.mailersend.com/v1/identities?page=1\",\"last\":\"https://api.mailersend.com/v1/identities?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"path\":\"https://api.mailersend.com/v1/identities\",\"per_page\":25,\"to\":1,\"total\":1}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SenderIdentitiesTest_TestGetIdentity().json b/src/test/resources/fixtures/SenderIdentitiesTest_TestGetIdentity().json
new file mode 100644
index 0000000..964ea21
--- /dev/null
+++ b/src/test/resources/fixtures/SenderIdentitiesTest_TestGetIdentity().json
@@ -0,0 +1 @@
+{"48ecd23b571736c6db90b2dd738525c61e79de13":{"body":"{\"data\":{\"id\":\"ident-id-123\",\"email\":\"test@example.com\",\"name\":\"Test Identity\",\"reply_to_email\":\"reply@example.com\",\"reply_to_name\":\"Reply Name\",\"is_verified\":true,\"resends\":0,\"add_note\":false,\"personal_note\":null,\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\"}}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SenderIdentitiesTest_TestGetIdentityByEmail().json b/src/test/resources/fixtures/SenderIdentitiesTest_TestGetIdentityByEmail().json
new file mode 100644
index 0000000..012991a
--- /dev/null
+++ b/src/test/resources/fixtures/SenderIdentitiesTest_TestGetIdentityByEmail().json
@@ -0,0 +1 @@
+{"46b7d92a1c8db9dbf799edd70b02418bfcb656c1":{"body":"{\"data\":{\"id\":\"ident-id-123\",\"email\":\"test@example.com\",\"name\":\"Test Identity\",\"reply_to_email\":\"reply@example.com\",\"reply_to_name\":\"Reply Name\",\"is_verified\":true,\"resends\":0,\"add_note\":false,\"personal_note\":null,\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\"}}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SenderIdentitiesTest_TestResendConfirmation().json b/src/test/resources/fixtures/SenderIdentitiesTest_TestResendConfirmation().json
new file mode 100644
index 0000000..1cad12a
--- /dev/null
+++ b/src/test/resources/fixtures/SenderIdentitiesTest_TestResendConfirmation().json
@@ -0,0 +1 @@
+{"ed03af7efe00b43697aa209ad99930778d5342aa":{"body":"{\"data\":{\"id\":\"ident-id-123\",\"email\":\"test@example.com\",\"name\":\"Test Identity\",\"reply_to_email\":\"reply@example.com\",\"reply_to_name\":\"Reply Name\",\"is_verified\":false,\"resends\":1,\"add_note\":false,\"personal_note\":null,\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\"}}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SenderIdentitiesTest_TestUpdateIdentity().json b/src/test/resources/fixtures/SenderIdentitiesTest_TestUpdateIdentity().json
new file mode 100644
index 0000000..94b8f1e
--- /dev/null
+++ b/src/test/resources/fixtures/SenderIdentitiesTest_TestUpdateIdentity().json
@@ -0,0 +1 @@
+{"8644af623f56ffe80d35cec25779f7415d7b5d24":{"body":"{\"data\":{\"id\":\"ident-id-123\",\"email\":\"test@example.com\",\"name\":\"Updated Identity\",\"reply_to_email\":\"reply@example.com\",\"reply_to_name\":\"Reply Name\",\"is_verified\":true,\"resends\":0,\"add_note\":false,\"personal_note\":null,\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\"}}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SenderIdentitiesTest_TestUpdateIdentityByEmail().json b/src/test/resources/fixtures/SenderIdentitiesTest_TestUpdateIdentityByEmail().json
new file mode 100644
index 0000000..600188c
--- /dev/null
+++ b/src/test/resources/fixtures/SenderIdentitiesTest_TestUpdateIdentityByEmail().json
@@ -0,0 +1 @@
+{"6485e6329c2cd707f076855b67dc2c5a203dab1c":{"body":"{\"data\":{\"id\":\"ident-id-123\",\"email\":\"test@example.com\",\"name\":\"Updated Identity\",\"reply_to_email\":\"reply@example.com\",\"reply_to_name\":\"Reply Name\",\"is_verified\":true,\"resends\":0,\"add_note\":false,\"personal_note\":null,\"domain\":{\"id\":\"jpzkmgq7e5vl059v\",\"name\":\"test-sdk.com\"}}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmsActivitiesTest_TestGetActivitiesWithSmsNumberIdFilter().json b/src/test/resources/fixtures/SmsActivitiesTest_TestGetActivitiesWithSmsNumberIdFilter().json
new file mode 100644
index 0000000..bcab4bc
--- /dev/null
+++ b/src/test/resources/fixtures/SmsActivitiesTest_TestGetActivitiesWithSmsNumberIdFilter().json
@@ -0,0 +1 @@
+{"7752baca5d96cdc1a4b0124d96dbde89fe9c18e9":{"body":"{\"data\":[{\"from\":\"+18133657349\",\"to\":\"+18332552485\",\"content\":\"test sms\",\"created_at\":\"2022-09-14T08:00:00.000000Z\",\"status\":\"sent\",\"sms_message_id\":\"sms-msg-id-test-1\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-activity?page=1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-activity?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-activity\",\"per_page\":\"25\",\"to\":1,\"total\":1}}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmsActivitiesTest_TestGetActivitiesWithStatusFilter().json b/src/test/resources/fixtures/SmsActivitiesTest_TestGetActivitiesWithStatusFilter().json
new file mode 100644
index 0000000..afc2181
--- /dev/null
+++ b/src/test/resources/fixtures/SmsActivitiesTest_TestGetActivitiesWithStatusFilter().json
@@ -0,0 +1 @@
+{"df5fd477c855940071b42c6951997413b17225f8":{"body":"{\"data\":[{\"from\":\"+18133657349\",\"to\":\"+18332552485\",\"content\":\"test sms\",\"created_at\":\"2022-09-14T08:00:00.000000Z\",\"status\":\"sent\",\"sms_message_id\":\"sms-msg-id-test-1\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-activity?page=1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-activity?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-activity\",\"per_page\":\"25\",\"to\":1,\"total\":1}}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmsActivitiesTest_TestGetSmsActivities().json b/src/test/resources/fixtures/SmsActivitiesTest_TestGetSmsActivities().json
new file mode 100644
index 0000000..514bae6
--- /dev/null
+++ b/src/test/resources/fixtures/SmsActivitiesTest_TestGetSmsActivities().json
@@ -0,0 +1 @@
+{"7f5760560bb49771e39eca369313d9c28de9e9c6":{"body":"{\"data\":[{\"from\":\"+18133657349\",\"to\":\"+18332552485\",\"content\":\"test sms\",\"created_at\":\"2022-09-14T08:00:00.000000Z\",\"status\":\"sent\",\"sms_message_id\":\"sms-msg-id-test-1\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-activity?page=1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-activity?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-activity\",\"per_page\":\"25\",\"to\":1,\"total\":1}}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmsActivitiesTest_TestGetSmsMessageActivity().json b/src/test/resources/fixtures/SmsActivitiesTest_TestGetSmsMessageActivity().json
new file mode 100644
index 0000000..e1370f7
--- /dev/null
+++ b/src/test/resources/fixtures/SmsActivitiesTest_TestGetSmsMessageActivity().json
@@ -0,0 +1 @@
+{"9e908c321317359dc1132fcf29e8c1706d19b81c":{"body":"{\"data\":{\"id\":\"sms-msg-id-test-1\",\"from\":\"+18133657349\",\"to\":[\"+18332552485\"],\"text\":\"test sms\",\"created_at\":\"2022-09-14T08:00:00.000000Z\",\"sms\":[{\"id\":\"sms-id-1\",\"from\":\"+18133657349\",\"to\":\"+18332552485\",\"text\":\"test sms\",\"status\":\"sent\",\"segment_count\":1,\"error_type\":null,\"error_description\":null,\"created_at\":\"2022-09-14T08:00:00.000000Z\"}],\"sms_activity\":[{\"from\":\"+18133657349\",\"to\":\"+18332552485\",\"content\":\"test sms\",\"created_at\":\"2022-09-14T08:00:00.000000Z\",\"status\":\"sent\",\"sms_message_id\":\"sms-msg-id-test-1\"}]}}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmsMessagesTest_TestGetSingleSmsMessage().json b/src/test/resources/fixtures/SmsMessagesTest_TestGetSingleSmsMessage().json
new file mode 100644
index 0000000..5c482cb
--- /dev/null
+++ b/src/test/resources/fixtures/SmsMessagesTest_TestGetSingleSmsMessage().json
@@ -0,0 +1 @@
+{"9e908c321317359dc1132fcf29e8c1706d19b81c":{"body":"{\"data\":{\"id\":\"sms-msg-id-test-1\",\"from\":\"+18133657349\",\"to\":[\"+18332552485\"],\"text\":\"test sms\",\"paused\":false,\"created_at\":\"2022-09-14T08:00:00.000000Z\",\"sms\":null}}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmsMessagesTest_TestGetSmsMessages().json b/src/test/resources/fixtures/SmsMessagesTest_TestGetSmsMessages().json
new file mode 100644
index 0000000..8725920
--- /dev/null
+++ b/src/test/resources/fixtures/SmsMessagesTest_TestGetSmsMessages().json
@@ -0,0 +1 @@
+{"ac53aea8a2a61c65cfb7f30ef48fa0c7738f21a9":{"body":"{\"data\":[{\"id\":\"sms-msg-id-test-1\",\"from\":\"+18133657349\",\"to\":[\"+18332552485\"],\"text\":\"test sms\",\"paused\":false,\"created_at\":\"2022-09-14T08:00:00.000000Z\",\"sms\":null}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-messages?page=1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-messages?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-messages\",\"per_page\":\"25\",\"to\":1,\"total\":1}}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmsPhoneNumbersTest_TestDeletePhoneNumber().json b/src/test/resources/fixtures/SmsPhoneNumbersTest_TestDeletePhoneNumber().json
new file mode 100644
index 0000000..e1d5e26
--- /dev/null
+++ b/src/test/resources/fixtures/SmsPhoneNumbersTest_TestDeletePhoneNumber().json
@@ -0,0 +1 @@
+{"118cbf45a40e12a2fa825356cd78f3012df607be":{"body":"","headers":{":status":["204"]},"statusCode":204}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmsPhoneNumbersTest_TestPhoneNumbersWithPausedFilter().json b/src/test/resources/fixtures/SmsPhoneNumbersTest_TestPhoneNumbersWithPausedFilter().json
new file mode 100644
index 0000000..bd67a3f
--- /dev/null
+++ b/src/test/resources/fixtures/SmsPhoneNumbersTest_TestPhoneNumbersWithPausedFilter().json
@@ -0,0 +1 @@
+{"570aae681c91079739326246cc9b9a37f547dec5":{"body":"{\"data\":[{\"id\":\"3yxj6lj9x14do2rm\",\"telephone_number\":\"+18133657349\",\"paused\":true,\"created_at\":\"2022-08-01T15:33:47.000000Z\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-numbers?page=1\",\"last\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-numbers?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"links\":[],\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-numbers\",\"per_page\":\"25\",\"to\":1,\"total\":1}}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmsPhoneNumbersTest_TestUpdatePhoneNumber().json b/src/test/resources/fixtures/SmsPhoneNumbersTest_TestUpdatePhoneNumber().json
new file mode 100644
index 0000000..2f68b6c
--- /dev/null
+++ b/src/test/resources/fixtures/SmsPhoneNumbersTest_TestUpdatePhoneNumber().json
@@ -0,0 +1 @@
+{"c71e92843b599d99e43f3a315448afed1f410fdd":{"body":"{\"data\":{\"id\":\"3yxj6lj9x14do2rm\",\"telephone_number\":\"+18133657349\",\"paused\":true,\"created_at\":\"2022-08-01T15:33:47.000000Z\"}}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmsRecipientsTest_TestSmsRecipientsWithSmsNumberIdFilter().json b/src/test/resources/fixtures/SmsRecipientsTest_TestSmsRecipientsWithSmsNumberIdFilter().json
new file mode 100644
index 0000000..5b359bc
--- /dev/null
+++ b/src/test/resources/fixtures/SmsRecipientsTest_TestSmsRecipientsWithSmsNumberIdFilter().json
@@ -0,0 +1 @@
+{"4521cc2ba958979dd7bb5541956907c3e2bbdb0d":{"body":"{\"data\":[{\"id\":\"627e7503d30078fb2208cc83\",\"number\":\"+18332552485\",\"status\":\"active\",\"opted_out_at\":null,\"opt_out_source\":null,\"created_at\":\"2022-05-13T15:10:59.444000Z\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-recipients?page=1\",\"last\":null,\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-recipients\",\"per_page\":\"25\",\"to\":1}}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmsRecipientsTest_TestSmsRecipientsWithStatusFilter().json b/src/test/resources/fixtures/SmsRecipientsTest_TestSmsRecipientsWithStatusFilter().json
new file mode 100644
index 0000000..ca082ea
--- /dev/null
+++ b/src/test/resources/fixtures/SmsRecipientsTest_TestSmsRecipientsWithStatusFilter().json
@@ -0,0 +1 @@
+{"4c61ad91ca9bb04835d4fec5eacaafd80c979cbd":{"body":"{\"data\":[{\"id\":\"627e7503d30078fb2208cc83\",\"number\":\"+18332552485\",\"status\":\"opt_out\",\"opted_out_at\":null,\"opt_out_source\":null,\"created_at\":\"2022-05-13T15:10:59.444000Z\"}],\"links\":{\"first\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-recipients?page=1\",\"last\":null,\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"path\":\"https:\\/\\/api.mailersend.com\\/v1\\/sms-recipients\",\"per_page\":\"25\",\"to\":1}}","headers":{":status":["200"],"content-type":["application/json"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmtpUsersTest_testCanCreateSmtpUser().json b/src/test/resources/fixtures/SmtpUsersTest_testCanCreateSmtpUser().json
new file mode 100644
index 0000000..aaf3544
--- /dev/null
+++ b/src/test/resources/fixtures/SmtpUsersTest_testCanCreateSmtpUser().json
@@ -0,0 +1 @@
+{"b6ac27016b7e2050f069f7ecb9aae52ee7b2a4dd":{"body":"{\"data\":{\"id\":\"480xl1qpeorzeg65\",\"name\":\"Support\",\"username\":\"MS_8PerdM@mailerlite.com\",\"password\":\"87GoZePLsPEKiGZR\",\"enabled\":true,\"accessed_at\":null,\"server\":\"smtp.mailersend.net\",\"port\":587,\"domain_id\":\"jpzkmgq7e5vl059v\"}}","headers":{":status":["201"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["58"]},"statusCode":201}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmtpUsersTest_testCanDeleteSmtpUser().json b/src/test/resources/fixtures/SmtpUsersTest_testCanDeleteSmtpUser().json
new file mode 100644
index 0000000..a1672a2
--- /dev/null
+++ b/src/test/resources/fixtures/SmtpUsersTest_testCanDeleteSmtpUser().json
@@ -0,0 +1 @@
+{"41980ee685a52d140be909d5cb8375d3a918d150":{"body":"","headers":{":status":["204"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":204}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmtpUsersTest_testCanGetSingleSmtpUser().json b/src/test/resources/fixtures/SmtpUsersTest_testCanGetSingleSmtpUser().json
new file mode 100644
index 0000000..ae14cab
--- /dev/null
+++ b/src/test/resources/fixtures/SmtpUsersTest_testCanGetSingleSmtpUser().json
@@ -0,0 +1 @@
+{"240f501e182e3ef78f955c3ee1d3db41f937463b":{"body":"{\"data\":{\"id\":\"0wkg2zj19ovx5py7\",\"name\":\"Support SMTP\",\"username\":\"MS_bGQ0nV@mailerlite.com\",\"password\":\"W3XCfDM6NWs69puR\",\"enabled\":true,\"accessed_at\":null,\"server\":\"smtp.mailersend.net\",\"port\":587,\"domain_id\":\"jpzkmgq7e5vl059v\"}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmtpUsersTest_testCanGetSmtpUsers().json b/src/test/resources/fixtures/SmtpUsersTest_testCanGetSmtpUsers().json
new file mode 100644
index 0000000..30e089f
--- /dev/null
+++ b/src/test/resources/fixtures/SmtpUsersTest_testCanGetSmtpUsers().json
@@ -0,0 +1 @@
+{"9d3a6524dc72ebc8c2d2e3690ce91bd86ffe8e69":{"body":"{\"data\":[{\"id\":\"0wkg2zj19ovx5py7\",\"name\":\"Support SMTP\",\"username\":\"MS_bGQ0nV@mailerlite.com\",\"password\":\"W3XCfDM6NWs69puR\",\"enabled\":true,\"accessed_at\":null,\"server\":\"smtp.mailersend.net\",\"port\":587,\"domain_id\":\"jpzkmgq7e5vl059v\"}]}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmtpUsersTest_testCanGetSmtpUsersWithPagination().json b/src/test/resources/fixtures/SmtpUsersTest_testCanGetSmtpUsersWithPagination().json
new file mode 100644
index 0000000..1b8a3e6
--- /dev/null
+++ b/src/test/resources/fixtures/SmtpUsersTest_testCanGetSmtpUsersWithPagination().json
@@ -0,0 +1 @@
+{"fbaf6092154dcda004de924990a795b6be1f785a":{"body":"{\"data\":[{\"id\":\"0wkg2zj19ovx5py7\",\"name\":\"Support SMTP\",\"username\":\"MS_bGQ0nV@mailerlite.com\",\"password\":\"W3XCfDM6NWs69puR\",\"enabled\":true,\"accessed_at\":null,\"server\":\"smtp.mailersend.net\",\"port\":587,\"domain_id\":\"jpzkmgq7e5vl059v\"}]}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmtpUsersTest_testCanGetSmtpUsers_with_pagination().json b/src/test/resources/fixtures/SmtpUsersTest_testCanGetSmtpUsers_with_pagination().json
new file mode 100644
index 0000000..b2253dd
--- /dev/null
+++ b/src/test/resources/fixtures/SmtpUsersTest_testCanGetSmtpUsers_with_pagination().json
@@ -0,0 +1 @@
+{"fbaf6092154dcda004de924990a795b6be1f785a":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"alt-svc":["h3\u003d\":443\"; ma\u003d86400"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["9fa09a52698141f6-LIS"],"content-type":["application/json"],"date":["Mon, 11 May 2026 10:46:57 GMT"],"server":["cloudflare"],"x-envoy-upstream-service-time":["76"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmtpUsersTest_testCanUpdateSmtpUser().json b/src/test/resources/fixtures/SmtpUsersTest_testCanUpdateSmtpUser().json
new file mode 100644
index 0000000..89ad3f3
--- /dev/null
+++ b/src/test/resources/fixtures/SmtpUsersTest_testCanUpdateSmtpUser().json
@@ -0,0 +1 @@
+{"b60c88c96cfb342e4492f4b0390717cd21497a3e":{"body":"{\"data\":{\"id\":\"0wkg2zj19ovx5py7\",\"name\":\"Support SMTP\",\"username\":\"MS_bGQ0nV@mailerlite.com\",\"password\":\"W3XCfDM6NWs69puR\",\"enabled\":false,\"accessed_at\":null,\"server\":\"smtp.mailersend.net\",\"port\":587,\"domain_id\":\"jpzkmgq7e5vl059v\"}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["58"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmtpUsersTest_testDeleteSmtpUserWithInvalidIdFails().json b/src/test/resources/fixtures/SmtpUsersTest_testDeleteSmtpUserWithInvalidIdFails().json
new file mode 100644
index 0000000..f88b5ed
--- /dev/null
+++ b/src/test/resources/fixtures/SmtpUsersTest_testDeleteSmtpUserWithInvalidIdFails().json
@@ -0,0 +1 @@
+{"24410ba76f4ad5e1acf984985bfda98678f82cdb":{"body":"{\"message\":\"Not Found\"}","headers":{":status":["404"],"content-type":["application/json"]},"statusCode":404}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmtpUsersTest_testGetSmtpUserWithInvalidIdFails().json b/src/test/resources/fixtures/SmtpUsersTest_testGetSmtpUserWithInvalidIdFails().json
new file mode 100644
index 0000000..a5f67c5
--- /dev/null
+++ b/src/test/resources/fixtures/SmtpUsersTest_testGetSmtpUserWithInvalidIdFails().json
@@ -0,0 +1 @@
+{"43ac1644c58882b7d1cdf7fb0cdefa786d6c599a":{"body":"{\"message\":\"Not Found\"}","headers":{":status":["404"],"content-type":["application/json"]},"statusCode":404}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/SmtpUsersTest_testInvalidTokenFailsWith401OnListSmtpUsers().json b/src/test/resources/fixtures/SmtpUsersTest_testInvalidTokenFailsWith401OnListSmtpUsers().json
new file mode 100644
index 0000000..bea50c5
--- /dev/null
+++ b/src/test/resources/fixtures/SmtpUsersTest_testInvalidTokenFailsWith401OnListSmtpUsers().json
@@ -0,0 +1 @@
+{"5fe4b030b4f65eedaca1bd2de3cdcc25b142561c":{"body":"{\"message\":\"Unauthenticated.\"}","headers":{":status":["401"],"content-type":["application/json"]},"statusCode":401}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/TokensTest_TestGetToken().json b/src/test/resources/fixtures/TokensTest_TestGetToken().json
new file mode 100644
index 0000000..124b51a
--- /dev/null
+++ b/src/test/resources/fixtures/TokensTest_TestGetToken().json
@@ -0,0 +1 @@
+{"1ed0ca68aeb62510e92cb7931aaf0a890e882de2":{"body":"{\"data\":{\"id\":\"865133ae500de599223a523d764877d7d3a4581ab24661adb044e787692cd6a5503e55fb8c700a03\",\"name\":\"My Token\",\"status\":\"pause\",\"scopes\":[\"email_full\",\"analytics_full\"],\"created_at\":\"2022-08-19T13:25:53.000000Z\"}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/TokensTest_TestGetTokens().json b/src/test/resources/fixtures/TokensTest_TestGetTokens().json
new file mode 100644
index 0000000..48a7e82
--- /dev/null
+++ b/src/test/resources/fixtures/TokensTest_TestGetTokens().json
@@ -0,0 +1 @@
+{"e81cee347d6303a9f4753bc5ee37e8d6bf5fec39":{"body":"{\"data\":[{\"id\":\"865133ae500de599223a523d764877d7d3a4581ab24661adb044e787692cd6a5503e55fb8c700a03\",\"name\":\"My Token\",\"status\":\"pause\",\"scopes\":[\"email_full\",\"analytics_full\"],\"created_at\":\"2022-08-19T13:25:53.000000Z\"}],\"links\":{\"first\":\"https://api.mailersend.com/v1/token?page=1\",\"last\":\"https://api.mailersend.com/v1/token?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"path\":\"https://api.mailersend.com/v1/token\",\"per_page\":25,\"to\":1,\"total\":1}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/TokensTest_TestUpdateTokenNameAndStatus().json b/src/test/resources/fixtures/TokensTest_TestUpdateTokenNameAndStatus().json
new file mode 100644
index 0000000..d3be64a
--- /dev/null
+++ b/src/test/resources/fixtures/TokensTest_TestUpdateTokenNameAndStatus().json
@@ -0,0 +1 @@
+{"e06799dd4ba1d4da68eac3d733949330de01c714":{"body":"{\"data\":{\"id\":\"865133ae500de599223a523d764877d7d3a4581ab24661adb044e787692cd6a5503e55fb8c700a03\",\"name\":\"Updated Name\",\"status\":\"pause\",\"created_at\":\"2022-08-19T13:25:53.000000Z\"}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/TokensTest_UpdateToken().json b/src/test/resources/fixtures/TokensTest_UpdateToken().json
index 2754239..436c31f 100644
--- a/src/test/resources/fixtures/TokensTest_UpdateToken().json
+++ b/src/test/resources/fixtures/TokensTest_UpdateToken().json
@@ -1 +1 @@
-{"f86c3719f89591b904a0acfebbedbdecb579a0ad":{"body":"{\"data\":{\"id\":\"865133ae500de599223a523d764877d7d3a4581ab24661adb044e787692cd6a5503e55fb8c700a03\",\"name\":\"To delete\\/pause\",\"status\":\"pause\",\"created_at\":\"2022-08-19T13:27:02.000000Z\"}}","headers":{":status":["200"],"cache-control":["no-cache, private"],"cf-cache-status":["DYNAMIC"],"cf-ray":["73d33b645cf138d6-ATH"],"content-type":["application/json"],"date":["Fri, 19 Aug 2022 13:28:22 GMT"],"expect-ct":["max-age\u003d604800, report-uri\u003d\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""],"server":["cloudflare"],"strict-transport-security":["max-age\u003d15724800; includeSubDomains"],"x-apiquota-remaining":["-1"],"x-apiquota-reset":["2022-08-20T00:00:00Z"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
+{"c2abab030079802aabbbb7b73965454c3d110984":{"body":"{\"data\":{\"id\":\"865133ae500de599223a523d764877d7d3a4581ab24661adb044e787692cd6a5503e55fb8c700a03\",\"name\":\"To delete/pause\",\"status\":\"pause\",\"created_at\":\"2022-08-19T13:27:02.000000Z\"}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/UsersTest_TestDeleteInvite().json b/src/test/resources/fixtures/UsersTest_TestDeleteInvite().json
new file mode 100644
index 0000000..69a328d
--- /dev/null
+++ b/src/test/resources/fixtures/UsersTest_TestDeleteInvite().json
@@ -0,0 +1 @@
+{"af4ccf159217b35458b146d75000cc406206abe3":{"body":"","headers":{":status":["204"],"content-type":["text/html; charset=UTF-8"]},"statusCode":204}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/UsersTest_TestDeleteUser().json b/src/test/resources/fixtures/UsersTest_TestDeleteUser().json
new file mode 100644
index 0000000..ffccabf
--- /dev/null
+++ b/src/test/resources/fixtures/UsersTest_TestDeleteUser().json
@@ -0,0 +1 @@
+{"3dfd36a7d35b66d15198707a89f8345fad143b4b":{"body":"","headers":{":status":["204"],"content-type":["text/html; charset=UTF-8"]},"statusCode":204}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/UsersTest_TestGetInvite().json b/src/test/resources/fixtures/UsersTest_TestGetInvite().json
new file mode 100644
index 0000000..46e2be6
--- /dev/null
+++ b/src/test/resources/fixtures/UsersTest_TestGetInvite().json
@@ -0,0 +1 @@
+{"5d501ac24030c42d3bc3b16aa1a2d400b8a8f9e7":{"body":"{\"data\":{\"id\":\"invite-id-123\",\"email\":\"newuser@example.com\",\"role\":\"Admin\",\"permissions\":[],\"requires_periodic_password_change\":false,\"created_at\":\"2022-08-19T13:25:53.000000Z\",\"updated_at\":\"2022-08-19T13:25:53.000000Z\"}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/UsersTest_TestGetInvites().json b/src/test/resources/fixtures/UsersTest_TestGetInvites().json
new file mode 100644
index 0000000..62fd5eb
--- /dev/null
+++ b/src/test/resources/fixtures/UsersTest_TestGetInvites().json
@@ -0,0 +1 @@
+{"1cd8564bae2d93b91cb03a8cda302cb4204c5527":{"body":"{\"data\":[{\"id\":\"invite-id-123\",\"email\":\"newuser@example.com\",\"role\":\"Admin\",\"permissions\":[],\"requires_periodic_password_change\":false,\"created_at\":\"2022-08-19T13:25:53.000000Z\",\"updated_at\":\"2022-08-19T13:25:53.000000Z\"}],\"links\":{\"first\":\"https://api.mailersend.com/v1/invites?page=1\",\"last\":\"https://api.mailersend.com/v1/invites?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"path\":\"https://api.mailersend.com/v1/invites\",\"per_page\":25,\"to\":1,\"total\":1}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/UsersTest_TestGetUser().json b/src/test/resources/fixtures/UsersTest_TestGetUser().json
new file mode 100644
index 0000000..ab11f78
--- /dev/null
+++ b/src/test/resources/fixtures/UsersTest_TestGetUser().json
@@ -0,0 +1 @@
+{"0d505081e06a4ea1373c223eb7ad3b2319afab22":{"body":"{\"data\":{\"id\":\"user-id-123\",\"email\":\"member@example.com\",\"name\":\"Test Member\",\"last_name\":\"Last\",\"avatar\":null,\"2fa\":false,\"role\":\"Admin\",\"permissions\":[],\"domains\":[],\"templates\":[],\"created_at\":\"2022-08-19T13:25:53.000000Z\",\"updated_at\":\"2022-08-19T13:25:53.000000Z\"}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/UsersTest_TestGetUsers().json b/src/test/resources/fixtures/UsersTest_TestGetUsers().json
new file mode 100644
index 0000000..f3abace
--- /dev/null
+++ b/src/test/resources/fixtures/UsersTest_TestGetUsers().json
@@ -0,0 +1 @@
+{"7c9e19af82c25b7262d6f3eb380aa987312f33a1":{"body":"{\"data\":[{\"id\":\"user-id-123\",\"email\":\"member@example.com\",\"name\":\"Test Member\",\"last_name\":\"Last\",\"avatar\":null,\"2fa\":false,\"role\":\"Admin\",\"permissions\":[],\"domains\":[],\"templates\":[],\"created_at\":\"2022-08-19T13:25:53.000000Z\",\"updated_at\":\"2022-08-19T13:25:53.000000Z\"}],\"links\":{\"first\":\"https://api.mailersend.com/v1/users?page=1\",\"last\":\"https://api.mailersend.com/v1/users?page=1\",\"prev\":null,\"next\":null},\"meta\":{\"current_page\":1,\"from\":1,\"last_page\":1,\"path\":\"https://api.mailersend.com/v1/users\",\"per_page\":25,\"to\":1,\"total\":1}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/UsersTest_TestInviteUser().json b/src/test/resources/fixtures/UsersTest_TestInviteUser().json
new file mode 100644
index 0000000..92261e3
--- /dev/null
+++ b/src/test/resources/fixtures/UsersTest_TestInviteUser().json
@@ -0,0 +1 @@
+{"b5c316aa6ff7b7f9beebd95f201e4d477fa1b405":{"body":"{\"data\":{\"id\":\"invite-id-123\",\"email\":\"newuser@example.com\",\"role\":\"Admin\",\"permissions\":[],\"requires_periodic_password_change\":false,\"created_at\":\"2022-08-19T13:25:53.000000Z\",\"updated_at\":\"2022-08-19T13:25:53.000000Z\"}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/UsersTest_TestResendInvite().json b/src/test/resources/fixtures/UsersTest_TestResendInvite().json
new file mode 100644
index 0000000..82191e6
--- /dev/null
+++ b/src/test/resources/fixtures/UsersTest_TestResendInvite().json
@@ -0,0 +1 @@
+{"5a27fc343fe984ea721b7a380651d1362a67ef13":{"body":"{\"data\":{\"id\":\"invite-id-123\",\"email\":\"newuser@example.com\",\"role\":\"Admin\",\"permissions\":[],\"requires_periodic_password_change\":false,\"created_at\":\"2022-08-19T13:25:53.000000Z\",\"updated_at\":\"2022-08-19T13:25:53.000000Z\"}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file
diff --git a/src/test/resources/fixtures/UsersTest_TestUpdateUser().json b/src/test/resources/fixtures/UsersTest_TestUpdateUser().json
new file mode 100644
index 0000000..143b104
--- /dev/null
+++ b/src/test/resources/fixtures/UsersTest_TestUpdateUser().json
@@ -0,0 +1 @@
+{"04084b114be381b78537bb7be94d86a944f094f6":{"body":"{\"data\":{\"id\":\"user-id-123\",\"email\":\"member@example.com\",\"name\":\"Test Member\",\"last_name\":\"Last\",\"avatar\":null,\"2fa\":false,\"role\":\"Manager\",\"permissions\":[],\"domains\":[],\"templates\":[],\"created_at\":\"2022-08-19T13:25:53.000000Z\",\"updated_at\":\"2022-08-19T13:30:00.000000Z\"}}","headers":{":status":["200"],"content-type":["application/json"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}}
\ No newline at end of file