The official Java SDK for Lettermint.
- Java 8 or higher
<dependency>
<groupId>co.lettermint</groupId>
<artifactId>lettermint</artifactId>
<version>2.0.0</version>
</dependency>implementation 'co.lettermint:lettermint:2.0.0'importco.lettermint.Lettermint;
importco.lettermint.endpoints.EmailEndpoint;
importco.lettermint.models.SendEmailResponse;
EmailEndpointemail = Lettermint.email("your-sending-token");
SendEmailResponseresponse = email
.from("sender@example.com")
.to("recipient@example.com")
.subject("Hello from Lettermint")
.html("<p>Hello World!</p>")
.send();
System.out.println("Message ID: " + response.getMessageId());Use a project sending token with Lettermint.email(...). Sending tokens authenticate with the x-lettermint-token header.
The SDK provides a fluent builder interface for composing emails:
importco.lettermint.Lettermint;
importco.lettermint.endpoints.EmailEndpoint;
importco.lettermint.models.SendEmailResponse;
importjava.util.HashMap;
importjava.util.Map;
EmailEndpointemail = Lettermint.email("your-sending-token");
Map<String, String> headers = newHashMap<>();
headers.put("X-Custom-Header", "value");
Map<String, Object> metadata = newHashMap<>();
metadata.put("userId", "123");
metadata.put("campaign", "welcome");
SendEmailResponseresponse = email// Sender
.from("John Doe <sender@example.com>")
// Recipients (varargs)
.to("recipient1@example.com", "recipient2@example.com")
.cc("cc@example.com")
.bcc("bcc@example.com")
.replyTo("reply@example.com")
// Content
.subject("Welcome!")
.html("<p>Hello <b>World</b></p>")
.text("Hello World")
// Custom headers
.headers(headers)
// Or add headers individually
.header("X-Another-Header", "value")
// Attachments
.attach("document.pdf", base64EncodedContent)
.attach("logo.png", base64EncodedContent, "logo") // Inline with content ID// Routing
.route("route-id")
// Metadata and tags
.metadata(metadata)
.tag("welcome", "onboarding")
// Idempotency
.idempotencyKey("unique-request-key")
.send();Existing constructor-based sending usage still works:
Lettermintlettermint = newLettermint("your-sending-token");
lettermint.email().from("sender@example.com").to("recipient@example.com").subject("Hello").send();importco.lettermint.models.api.SendMailRequest;
importco.lettermint.models.api.SendMailResponse;
importjava.util.Collections;
importjava.util.List;
SendMailRequestmessage = newSendMailRequest();
message.fromValue = "sender@example.com";
message.to = Collections.singletonList("recipient@example.com");
message.subject = "Hello from Lettermint";
message.text = "This is a batch email.";
List<SendMailResponse> response = Lettermint.email("your-sending-token")
.sendBatch(Collections.singletonList(message));Both sending and API clients support ping():
Stringpong = Lettermint.email("your-sending-token").ping();Use a team API token with Lettermint.api(...). API tokens authenticate with Authorization: Bearer ... and are separate from project sending tokens.
importco.lettermint.Lettermint;
importco.lettermint.api.ApiClient;
importco.lettermint.models.api.DomainIndexResponse;
importco.lettermint.models.api.TeamData;
importjava.util.Collections;
importjava.util.Map;
ApiClientapi = Lettermint.api("your-api-token");
Map<String, String> query = Collections.singletonMap("page[size]", "10");
DomainIndexResponsedomains = api.domains().list(query);
TeamDatateam = api.team().retrieve();
StringmessageHtml = api.messages().html("message-id");
Stringpong = api.ping();Endpoint groups are available as domains(), messages(), projects(), routes(), stats(), suppressions(), team(), and webhooks().
Verify webhook signatures to ensure requests are from Lettermint:
importco.lettermint.webhooks.Webhook;
importco.lettermint.exceptions.webhook.WebhookVerificationException;
importjava.util.Map;
StringrawPayload = "..."; // Raw JSON body from requestStringsignature = "..."; // Value of X-Lettermint-Signature headerStringsecret = "whsec_..."; // Your webhook signing secrettry {
Map<String, Object> payload = Webhook.verify(rawPayload, signature, secret);
Stringevent = (String) payload.get("event");
Map<String, Object> data = (Map<String, Object>) payload.get("data");
// Handle the webhook event
} catch (WebhookVerificationExceptione) {
// Invalid signature
}With custom timestamp tolerance (in seconds):
// Allow signatures up to 10 minutes oldMap<String, Object> payload = Webhook.verify(rawPayload, signature, secret, 600);
// Disable timestamp checkingMap<String, Object> payload = Webhook.verify(rawPayload, signature, secret, 0);The SDK uses unchecked exceptions that extend RuntimeException:
importco.lettermint.exceptions.*;
try {
lettermint.email()
.from("sender@example.com")
.to("recipient@example.com")
.subject("Test")
.send();
} catch (ValidationExceptione) {
// HTTP 422 - validation errorsSystem.err.println("Validation failed: " + e.getMessage());
System.err.println("Response: " + e.getResponseBody());
} catch (HttpRequestExceptione) {
// Other HTTP errorsSystem.err.println("HTTP " + e.getStatusCode() + ": " + e.getMessage());
} catch (LettermintExceptione) {
// Other SDK errors (including timeouts)System.err.println("Error: " + e.getMessage());
}importco.lettermint.exceptions.webhook.*;
try {
Webhook.verify(payload, signature, secret);
} catch (InvalidSignatureExceptione) {
// Signature doesn't match
} catch (TimestampToleranceExceptione) {
// Timestamp too oldSystem.err.println("Timestamp: " + e.getTimestamp());
System.err.println("Tolerance: " + e.getTolerance());
} catch (WebhookVerificationExceptione) {
// Other verification errors
}mvn clean install./gradlew buildmvn test./gradlew testMIT License - see LICENSE for details.