diff --git a/README.md b/README.md index b82fb5a..b4217af 100644 --- a/README.md +++ b/README.md @@ -1016,6 +1016,12 @@ The SDK returns an `Activities` object on successful send or throws a `MailerSen Through the `Activities` object you can get the list of activities, get the next page of results, convert an activity into an email for resend, etc. +> **Note on `suppressed` activities** +> +> `activity.suppressionReason` is only populated when `activity.type` is `suppressed`; it is `null` for every other activity type. Its possible values are `on_hold`, `hard_bounced`, `unsubscribed`, `spam_complained` and `blocklisted`. +> +> The `suppressed` activity type requires the Starter plan or above. + ### Get a list of activities ```java @@ -1037,6 +1043,8 @@ public void getActivities() { for (Activity activity : activities.activities) { System.out.println(activity.id); + System.out.println(activity.type); + System.out.println(activity.suppressionReason); // only set when type is "suppressed", null otherwise System.out.println(activity.createdAt.toString()); System.out.println(activity.email.from); @@ -1071,6 +1079,7 @@ public void getSingleActivity() { System.out.println(activity.id); System.out.println(activity.type); + System.out.println(activity.suppressionReason); // only set when type is "suppressed", null otherwise System.out.println(activity.createdAt.toString()); System.out.println(activity.email.from); @@ -1105,13 +1114,15 @@ public void getActivities() { Date dateFrom = DateUtils.addDays(new Date(), -30); // you'll need apache-commons for this Date dateTo = new Date(); - String events[] = {EventTypes.OPENED, EventTypes.SENT}; // check com.mailsersend.sdk.util.EventTypes for a full list of events + String events[] = {EventTypes.OPENED, EventTypes.SENT, EventTypes.SUPPRESSED}; // check com.mailsersend.sdk.util.EventTypes for a full list of events ActivitiesList activities = ms.activities().getActivities("domain id", page, limit, dateFrom, dateTo, events); for (Activity activity : activities.activities) { System.out.println(activity.id); + System.out.println(activity.type); + System.out.println(activity.suppressionReason); // only set when type is "suppressed", null otherwise } } catch (MailerSendException e) { diff --git a/src/main/java/com/mailersend/sdk/activities/Activity.java b/src/main/java/com/mailersend/sdk/activities/Activity.java index aefe93a..461ffd0 100644 --- a/src/main/java/com/mailersend/sdk/activities/Activity.java +++ b/src/main/java/com/mailersend/sdk/activities/Activity.java @@ -31,7 +31,14 @@ public class Activity { @SerializedName("type") public String type; - + + /** + * Only populated when type is EventTypes.SUPPRESSED. One of: on_hold, hard_bounced, + * unsubscribed, spam_complained, blocklisted. Null for every other activity type. + */ + @SerializedName("suppression_reason") + public String suppressionReason; + @SerializedName("email") public ActivityEmail email; diff --git a/src/main/java/com/mailersend/sdk/util/EventTypes.java b/src/main/java/com/mailersend/sdk/util/EventTypes.java index 6f5d02e..6b090a6 100644 --- a/src/main/java/com/mailersend/sdk/util/EventTypes.java +++ b/src/main/java/com/mailersend/sdk/util/EventTypes.java @@ -55,4 +55,7 @@ public class EventTypes { /** Constant SURVEY_SUBMITTED="survey_submitted" */ public static final String SURVEY_SUBMITTED = "survey_submitted"; + + /** Constant SUPPRESSED="suppressed" */ + public static final String SUPPRESSED = "suppressed"; } diff --git a/src/test/java/com/mailersend/sdk/tests/ActivitiesTest.java b/src/test/java/com/mailersend/sdk/tests/ActivitiesTest.java index da6c44c..5007b0e 100644 --- a/src/test/java/com/mailersend/sdk/tests/ActivitiesTest.java +++ b/src/test/java/com/mailersend/sdk/tests/ActivitiesTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -170,6 +171,72 @@ public void testActivitiesFilterByEvent() { } + /** + * Tests that the activities can be filtered by the suppressed event + * Fixed dates are used so that the recorded request hash (url + method + body) stays stable + * and the fixture can be replayed without hitting the API + */ + @Test + public void testActivitiesFilterBySuppressedEvent() { + + MailerSend ms = new MailerSend(); + ms.setToken(TestHelper.validToken); + + try { + + Date dateFrom = Date.from(Instant.parse("2024-01-01T00:00:00Z")); + Date dateTo = Date.from(Instant.parse("2024-01-31T00:00:00Z")); + + ActivitiesList activities = ms.activities().getActivities(TestHelper.domainId, 1, 100, dateFrom, dateTo, new String[] { EventTypes.SUPPRESSED }); + + assertTrue(activities.activities.length > 0); + + for (Activity activity : activities.activities) { + + assertEquals(EventTypes.SUPPRESSED, activity.type); + } + + } catch (MailerSendException e) { + + fail(); + } + } + + + /** + * Tests that the suppression_reason response field is deserialized for suppressed activities + * and is absent for activities of any other type + */ + @Test + public void testActivitySuppressionReason() { + + MailerSend ms = new MailerSend(); + ms.setToken(TestHelper.validToken); + + try { + + Date dateFrom = Date.from(Instant.parse("2024-01-01T00:00:00Z")); + Date dateTo = Date.from(Instant.parse("2024-01-31T00:00:00Z")); + + ActivitiesList activities = ms.activities().getActivities(TestHelper.domainId, 1, 25, dateFrom, dateTo, null); + + assertTrue(activities.activities.length > 1); + + Activity suppressed = activities.activities[0]; + assertEquals(EventTypes.SUPPRESSED, suppressed.type); + assertEquals("hard_bounced", suppressed.suppressionReason); + + Activity delivered = activities.activities[1]; + assertEquals(EventTypes.DELIVERED, delivered.type); + assertNull(delivered.suppressionReason); + + } catch (MailerSendException e) { + + fail(); + } + } + + /** * Tests the contents of a single activity */ diff --git a/src/test/resources/fixtures/ActivitiesTest_testActivitiesFilterBySuppressedEvent().json b/src/test/resources/fixtures/ActivitiesTest_testActivitiesFilterBySuppressedEvent().json new file mode 100644 index 0000000..2811497 --- /dev/null +++ b/src/test/resources/fixtures/ActivitiesTest_testActivitiesFilterBySuppressedEvent().json @@ -0,0 +1 @@ +{"a4f89c8beade0985d2f33e0a9bf17409f92e7961":{"body":"{\"data\":[{\"id\":\"65a4f0b5b1ffd57ddb0b5ee1\",\"created_at\":\"2024-01-15T10:09:09.604000Z\",\"updated_at\":\"2024-01-15T10:09:09.604000Z\",\"type\":\"suppressed\",\"suppression_reason\":\"hard_bounced\",\"email\":{\"id\":\"65a4f0a86f6d7fb43c0c4981\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"rejected\",\"tags\":[],\"created_at\":\"2024-01-15T10:08:56.358000Z\",\"updated_at\":\"2024-01-15T10:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"java@mailersend.com\",\"created_at\":\"2024-01-01T15:30:19.265000Z\",\"updated_at\":\"2024-01-01T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"65a4f0b5b1ffd57ddb0b5ee2\",\"created_at\":\"2024-01-15T10:09:09.604000Z\",\"updated_at\":\"2024-01-15T10:09:09.604000Z\",\"type\":\"suppressed\",\"suppression_reason\":\"blocklisted\",\"email\":{\"id\":\"65a4f0a86f6d7fb43c0c4982\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"rejected\",\"tags\":[],\"created_at\":\"2024-01-15T10:08:56.358000Z\",\"updated_at\":\"2024-01-15T10:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"java@mailersend.com\",\"created_at\":\"2024-01-01T15:30:19.265000Z\",\"updated_at\":\"2024-01-01T15:30:19.265000Z\",\"deleted_at\":\"\"}}}]}","headers":{":status":["200"],"cache-control":["no-cache, private"],"content-type":["application/json"],"date":["Wed, 31 Jan 2024 12:00:00 GMT"],"server":["cloudflare"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}} \ No newline at end of file diff --git a/src/test/resources/fixtures/ActivitiesTest_testActivitySuppressionReason().json b/src/test/resources/fixtures/ActivitiesTest_testActivitySuppressionReason().json new file mode 100644 index 0000000..944fb45 --- /dev/null +++ b/src/test/resources/fixtures/ActivitiesTest_testActivitySuppressionReason().json @@ -0,0 +1 @@ +{"64968426e89a594be46c6498f3fadc6a80d0c4c7":{"body":"{\"data\":[{\"id\":\"65a4f0b5b1ffd57ddb0b5ee3\",\"created_at\":\"2024-01-15T10:09:09.604000Z\",\"updated_at\":\"2024-01-15T10:09:09.604000Z\",\"type\":\"suppressed\",\"suppression_reason\":\"hard_bounced\",\"email\":{\"id\":\"65a4f0a86f6d7fb43c0c4983\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"rejected\",\"tags\":[],\"created_at\":\"2024-01-15T10:08:56.358000Z\",\"updated_at\":\"2024-01-15T10:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"java@mailersend.com\",\"created_at\":\"2024-01-01T15:30:19.265000Z\",\"updated_at\":\"2024-01-01T15:30:19.265000Z\",\"deleted_at\":\"\"}}},{\"id\":\"65a4f0b5b1ffd57ddb0b5ee4\",\"created_at\":\"2024-01-15T10:09:09.604000Z\",\"updated_at\":\"2024-01-15T10:09:09.604000Z\",\"type\":\"delivered\",\"email\":{\"id\":\"65a4f0a86f6d7fb43c0c4984\",\"from\":\"sender@test-sdk.com\",\"subject\":\"Subject\",\"text\":null,\"html\":null,\"status\":\"delivered\",\"tags\":[],\"created_at\":\"2024-01-15T10:08:56.358000Z\",\"updated_at\":\"2024-01-15T10:08:57.830000Z\",\"recipient\":{\"id\":\"62a2120ba4920c48900f2761\",\"email\":\"java@mailersend.com\",\"created_at\":\"2024-01-01T15:30:19.265000Z\",\"updated_at\":\"2024-01-01T15:30:19.265000Z\",\"deleted_at\":\"\"}}}]}","headers":{":status":["200"],"cache-control":["no-cache, private"],"content-type":["application/json"],"date":["Wed, 31 Jan 2024 12:00:00 GMT"],"server":["cloudflare"],"x-ratelimit-limit":["60"],"x-ratelimit-remaining":["59"]},"statusCode":200}} \ No newline at end of file