From 827cd124a183f1b73ae6f27ad7154755cb504fb2 Mon Sep 17 00:00:00 2001 From: Bjarn Bronsveld Date: Tue, 7 Jul 2026 22:41:29 +0200 Subject: [PATCH] Add latest Team API support --- .../java/co/lettermint/api/ApiClient.java | 4 ++ .../models/api/BlockedFileTypesResponse.java | 14 +++++ .../models/api/MessageEventType.java | 1 + .../co/lettermint/models/api/ProjectData.java | 3 + .../models/api/StoreProjectData.java | 3 + .../models/api/StoreSuppressionData.java | 2 +- .../models/api/UpdateProjectData.java | 3 + .../models/api/UpdateRouteData.java | 5 +- .../api/UpdateRouteInboundSettingsData.java | 16 +++++ .../models/api/UpdateRouteSettingsData.java | 22 +++++++ .../co/lettermint/models/api/VolumeTier.java | 1 + .../lettermint/models/api/WebhookEvent.java | 1 + .../java/co/lettermint/ApiClientTest.java | 59 +++++++++++++++++++ 13 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 src/main/java/co/lettermint/models/api/BlockedFileTypesResponse.java create mode 100644 src/main/java/co/lettermint/models/api/UpdateRouteInboundSettingsData.java create mode 100644 src/main/java/co/lettermint/models/api/UpdateRouteSettingsData.java diff --git a/src/main/java/co/lettermint/api/ApiClient.java b/src/main/java/co/lettermint/api/ApiClient.java index 4147469..b00b260 100644 --- a/src/main/java/co/lettermint/api/ApiClient.java +++ b/src/main/java/co/lettermint/api/ApiClient.java @@ -34,6 +34,10 @@ public String ping() { return client.getRaw("/ping").trim(); } + public BlockedFileTypesResponse blockedFileTypes() { + return client.get("/blocked-file-types", BlockedFileTypesResponse.class); + } + public DomainsEndpoint domains() { return domains; } diff --git a/src/main/java/co/lettermint/models/api/BlockedFileTypesResponse.java b/src/main/java/co/lettermint/models/api/BlockedFileTypesResponse.java new file mode 100644 index 0000000..e00f2c3 --- /dev/null +++ b/src/main/java/co/lettermint/models/api/BlockedFileTypesResponse.java @@ -0,0 +1,14 @@ +package co.lettermint.models.api; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class BlockedFileTypesResponse { + @JsonProperty("extensions") + public List extensions; + + @JsonProperty("mime_types") + public List mimeTypes; +} diff --git a/src/main/java/co/lettermint/models/api/MessageEventType.java b/src/main/java/co/lettermint/models/api/MessageEventType.java index e984106..4cca4f9 100644 --- a/src/main/java/co/lettermint/models/api/MessageEventType.java +++ b/src/main/java/co/lettermint/models/api/MessageEventType.java @@ -5,6 +5,7 @@ public final class MessageEventType { public static final String PROCESSED = "processed"; public static final String SUPPRESSED = "suppressed"; public static final String DELIVERED = "delivered"; + public static final String AUTOREPLIED = "auto_replied"; public static final String SOFTBOUNCED = "soft_bounced"; public static final String HARDBOUNCED = "hard_bounced"; public static final String SPAMCOMPLAINT = "spam_complaint"; diff --git a/src/main/java/co/lettermint/models/api/ProjectData.java b/src/main/java/co/lettermint/models/api/ProjectData.java index e771917..9b33780 100644 --- a/src/main/java/co/lettermint/models/api/ProjectData.java +++ b/src/main/java/co/lettermint/models/api/ProjectData.java @@ -15,6 +15,9 @@ public class ProjectData { @JsonProperty("smtp_enabled") public Boolean smtpEnabled; + @JsonProperty("redact_email_content") + public Boolean redactEmailContent; + @JsonProperty("default_route_id") public String defaultRouteId; diff --git a/src/main/java/co/lettermint/models/api/StoreProjectData.java b/src/main/java/co/lettermint/models/api/StoreProjectData.java index b912730..8ac6658 100644 --- a/src/main/java/co/lettermint/models/api/StoreProjectData.java +++ b/src/main/java/co/lettermint/models/api/StoreProjectData.java @@ -13,4 +13,7 @@ public class StoreProjectData { @JsonProperty("initial_routes") public InitialRoutes initialRoutes; + + @JsonProperty("short_token") + public Boolean shortToken; } diff --git a/src/main/java/co/lettermint/models/api/StoreSuppressionData.java b/src/main/java/co/lettermint/models/api/StoreSuppressionData.java index 5dd0bc8..08e392e 100644 --- a/src/main/java/co/lettermint/models/api/StoreSuppressionData.java +++ b/src/main/java/co/lettermint/models/api/StoreSuppressionData.java @@ -13,7 +13,7 @@ public class StoreSuppressionData { public SuppressionReason reason; @JsonProperty("scope") - public String scope; + public SuppressionScope scope; @JsonProperty("route_id") public String routeId; diff --git a/src/main/java/co/lettermint/models/api/UpdateProjectData.java b/src/main/java/co/lettermint/models/api/UpdateProjectData.java index 3fb0b01..2c4a84e 100644 --- a/src/main/java/co/lettermint/models/api/UpdateProjectData.java +++ b/src/main/java/co/lettermint/models/api/UpdateProjectData.java @@ -11,6 +11,9 @@ public class UpdateProjectData { @JsonProperty("smtp_enabled") public Boolean smtpEnabled; + @JsonProperty("redact_email_content") + public Boolean redactEmailContent; + @JsonProperty("default_route_id") public String defaultRouteId; } diff --git a/src/main/java/co/lettermint/models/api/UpdateRouteData.java b/src/main/java/co/lettermint/models/api/UpdateRouteData.java index 4d8ccbd..0978ddb 100644 --- a/src/main/java/co/lettermint/models/api/UpdateRouteData.java +++ b/src/main/java/co/lettermint/models/api/UpdateRouteData.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Map; @JsonIgnoreProperties(ignoreUnknown = true) public class UpdateRouteData { @@ -10,8 +9,8 @@ public class UpdateRouteData { public String name; @JsonProperty("settings") - public Map settings; + public UpdateRouteSettingsData settings; @JsonProperty("inbound_settings") - public Map inboundSettings; + public UpdateRouteInboundSettingsData inboundSettings; } diff --git a/src/main/java/co/lettermint/models/api/UpdateRouteInboundSettingsData.java b/src/main/java/co/lettermint/models/api/UpdateRouteInboundSettingsData.java new file mode 100644 index 0000000..f08235d --- /dev/null +++ b/src/main/java/co/lettermint/models/api/UpdateRouteInboundSettingsData.java @@ -0,0 +1,16 @@ +package co.lettermint.models.api; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class UpdateRouteInboundSettingsData { + @JsonProperty("inbound_domain") + public String inboundDomain; + + @JsonProperty("inbound_spam_threshold") + public Double inboundSpamThreshold; + + @JsonProperty("attachment_delivery") + public AttachmentDelivery attachmentDelivery; +} diff --git a/src/main/java/co/lettermint/models/api/UpdateRouteSettingsData.java b/src/main/java/co/lettermint/models/api/UpdateRouteSettingsData.java new file mode 100644 index 0000000..b0dda41 --- /dev/null +++ b/src/main/java/co/lettermint/models/api/UpdateRouteSettingsData.java @@ -0,0 +1,22 @@ +package co.lettermint.models.api; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class UpdateRouteSettingsData { + @JsonProperty("track_opens") + public Boolean trackOpens; + + @JsonProperty("track_clicks") + public Boolean trackClicks; + + @JsonProperty("disable_plaintext_generation") + public Boolean disablePlaintextGeneration; + + @JsonProperty("disable_hosted_unsubscribe") + public Boolean disableHostedUnsubscribe; + + @JsonProperty("redact_email_content") + public Boolean redactEmailContent; +} diff --git a/src/main/java/co/lettermint/models/api/VolumeTier.java b/src/main/java/co/lettermint/models/api/VolumeTier.java index ac1c743..25d82cf 100644 --- a/src/main/java/co/lettermint/models/api/VolumeTier.java +++ b/src/main/java/co/lettermint/models/api/VolumeTier.java @@ -5,6 +5,7 @@ public final class VolumeTier { public static final int VALUE_10000 = 10000; public static final int VALUE_50000 = 50000; public static final int VALUE_125000 = 125000; + public static final int VALUE_300000 = 300000; public static final int VALUE_500000 = 500000; public static final int VALUE_750000 = 750000; public static final int VALUE_1000000 = 1000000; diff --git a/src/main/java/co/lettermint/models/api/WebhookEvent.java b/src/main/java/co/lettermint/models/api/WebhookEvent.java index fe43e78..867efb1 100644 --- a/src/main/java/co/lettermint/models/api/WebhookEvent.java +++ b/src/main/java/co/lettermint/models/api/WebhookEvent.java @@ -4,6 +4,7 @@ public final class WebhookEvent { public static final String MESSAGECREATED = "message.created"; public static final String MESSAGESENT = "message.sent"; public static final String MESSAGEDELIVERED = "message.delivered"; + public static final String MESSAGEAUTOREPLIED = "message.auto_replied"; public static final String MESSAGEHARDBOUNCED = "message.hard_bounced"; public static final String MESSAGESOFTBOUNCED = "message.soft_bounced"; public static final String MESSAGESPAMCOMPLAINT = "message.spam_complaint"; diff --git a/src/test/java/co/lettermint/ApiClientTest.java b/src/test/java/co/lettermint/ApiClientTest.java index 4bb4c6b..3435591 100644 --- a/src/test/java/co/lettermint/ApiClientTest.java +++ b/src/test/java/co/lettermint/ApiClientTest.java @@ -50,6 +50,25 @@ void staticApiUsesBearerTokenAndRawPing() throws Exception { } } + @Test + void apiBlockedFileTypesUsesBearerToken() throws Exception { + try (MockWebServer server = new MockWebServer()) { + server.enqueue(new MockResponse() + .setHeader("Content-Type", "application/json") + .setBody("{\"extensions\":[\"exe\"],\"mime_types\":[\"application/x-msdownload\"]}")); + server.start(); + + ApiClient api = Lettermint.api("api-token", server.url("/v1").toString()); + co.lettermint.models.api.BlockedFileTypesResponse response = api.blockedFileTypes(); + + RecordedRequest request = server.takeRequest(); + assertEquals("/v1/blocked-file-types", request.getPath()); + assertEquals("Bearer api-token", request.getHeader("Authorization")); + assertNull(request.getHeader("x-lettermint-token")); + assertEquals("exe", response.extensions.get(0)); + } + } + @Test void sendsBatchEmailsWithTypedPayloads() throws Exception { try (MockWebServer server = new MockWebServer()) { @@ -119,6 +138,45 @@ void publicClientRejectsAbsoluteRequestPaths() throws Exception { assertEquals("Request path must be relative", exception.getMessage()); } + @Test + void generatedApiModelsMatchCurrentTeamSchema() { + assertEquals("auto_replied", co.lettermint.models.api.MessageEventType.AUTOREPLIED); + assertEquals("message.auto_replied", co.lettermint.models.api.WebhookEvent.MESSAGEAUTOREPLIED); + assertEquals(300000, co.lettermint.models.api.VolumeTier.VALUE_300000); + + co.lettermint.models.api.UpdateRouteSettingsData settings = new co.lettermint.models.api.UpdateRouteSettingsData(); + settings.redactEmailContent = true; + settings.disablePlaintextGeneration = false; + + co.lettermint.models.api.UpdateRouteInboundSettingsData inboundSettings = new co.lettermint.models.api.UpdateRouteInboundSettingsData(); + inboundSettings.inboundSpamThreshold = 3.0; + + co.lettermint.models.api.UpdateRouteData routeUpdate = new co.lettermint.models.api.UpdateRouteData(); + routeUpdate.settings = settings; + routeUpdate.inboundSettings = inboundSettings; + + co.lettermint.models.api.UpdateProjectData projectUpdate = new co.lettermint.models.api.UpdateProjectData(); + projectUpdate.redactEmailContent = false; + + co.lettermint.models.api.ProjectData project = new co.lettermint.models.api.ProjectData(); + project.redactEmailContent = true; + + co.lettermint.models.api.StoreProjectData projectCreate = new co.lettermint.models.api.StoreProjectData(); + projectCreate.shortToken = true; + + co.lettermint.models.api.BlockedFileTypesResponse blockedFileTypes = new co.lettermint.models.api.BlockedFileTypesResponse(); + blockedFileTypes.extensions = Collections.singletonList("exe"); + blockedFileTypes.mimeTypes = Collections.singletonList("application/x-msdownload"); + + assertFalse(routeUpdate.settings.disablePlaintextGeneration); + assertEquals(3.0, routeUpdate.inboundSettings.inboundSpamThreshold); + assertFalse(projectUpdate.redactEmailContent); + assertTrue(projectCreate.shortToken); + assertTrue(project.redactEmailContent); + assertEquals("global", co.lettermint.models.api.SuppressionScope.GLOBAL); + assertEquals("application/x-msdownload", blockedFileTypes.mimeTypes.get(0)); + } + @Test void apiExposesDocumentedOperations() throws Exception { ApiClient api = Lettermint.api("api-token"); @@ -131,6 +189,7 @@ void apiExposesDocumentedOperations() throws Exception { methods.put("domain.verifySpecificDnsRecord", api.domains().getClass().getMethod("verifyDnsRecord", String.class, String.class)); methods.put("domain.updateProjects", api.domains().getClass().getMethod("updateProjects", String.class, co.lettermint.models.api.UpdateDomainProjectsData.class)); methods.put("v1.ping", api.getClass().getMethod("ping")); + methods.put("v1.blockedFileTypes", api.getClass().getMethod("blockedFileTypes")); methods.put("message.index", api.messages().getClass().getMethod("list")); methods.put("message.show", api.messages().getClass().getMethod("retrieve", String.class)); methods.put("message.events", api.messages().getClass().getMethod("events", String.class));