SDKs
Java SDK
Official Java SDK for the Sendry email API.
Installation
Maven
<dependency>
<groupId>dev.sendry</groupId>
<artifactId>sendry</artifactId>
<version>0.1.0</version>
</dependency>
Gradle (Kotlin DSL)
dependencies {
implementation("dev.sendry:sendry:0.1.0")
}
Requires Java 17 or newer. Built on the JDK's native
java.net.http.HttpClient — no third-party HTTP layer.
Initialization
import dev.sendry.Sendry;
import dev.sendry.SendryConfig;
import java.time.Duration;
// Simple initialization
Sendry sendry = new Sendry(System.getenv("SENDRY_API_KEY"));
// With options
SendryConfig cfg = SendryConfig.builder("sn_live_...")
.baseUrl("https://api.sendry.online")
.timeout(Duration.ofSeconds(30))
.retries(2)
.build();
Sendry sendry = new Sendry(cfg);
Emails
import dev.sendry.types.SendEmailResponse;
import dev.sendry.types.Email;
import dev.sendry.types.PaginatedResponse;
import java.util.List;
import java.util.Map;
// Send a single email
SendEmailResponse res = sendry.emails.send(
"from", "Acme <hello@acme.com>",
"to", "user@example.com",
"subject", "Welcome!",
"html", "<h1>Welcome to Acme!</h1>"
);
System.out.println(res.id() + " " + res.status());
// Send to multiple recipients
sendry.emails.send(
"from", "hello@acme.com",
"to", List.of("alice@example.com", "bob@example.com"),
"subject", "Team announcement",
"html", "<p>Big news...</p>"
);
// Send using a template
sendry.emails.send(
"from", "hello@acme.com",
"to", "user@example.com",
"template_id", "tmpl_abc123",
"variables", Map.of("name", "Alice", "plan", "Pro")
);
// Batch send
sendry.emails.sendBatch(Map.of(
"from", "hello@acme.com",
"subject", "Order update",
"emails", List.of(
Map.of("to", "alice@example.com", "html", "<p>Alice, shipped!</p>"),
Map.of("to", "bob@example.com", "html", "<p>Bob, shipped!</p>")
)
));
// Get email
Email email = sendry.emails.get("em_abc123");
System.out.println(email.status());
// List emails
PaginatedResponse<Email> page = sendry.emails.list(
Map.of("limit", 25, "status", "delivered")
);
for (Email e : page.data()) {
System.out.println(e.id() + " " + e.subject());
}
// Cancel
sendry.emails.cancel("em_abc123");
Domains
import dev.sendry.types.Domain;
// Add a domain
Domain domain = sendry.domains.create("acme.com");
for (Domain.DnsRecord r : domain.dnsRecords()) {
System.out.printf("%s %s → %s%n", r.type(), r.host(), r.value());
}
// Verify
sendry.domains.verify("dom_abc123");
// List, get, delete
sendry.domains.list();
sendry.domains.get("dom_abc123");
sendry.domains.remove("dom_abc123");
Contacts & Audiences
import dev.sendry.types.Contact;
import dev.sendry.types.Audience;
Contact contact = sendry.contacts.create(Map.of(
"email", "jane@example.com",
"first_name", "Jane",
"last_name", "Doe"
));
Audience audience = sendry.audiences.create(Map.of(
"name", "Newsletter Subscribers"
));
sendry.audiences.addContacts(audience.id(), Map.of(
"contact_ids", List.of(contact.id())
));
Analytics
import dev.sendry.types.AnalyticsResponse;
AnalyticsResponse stats = sendry.analytics.stats(Map.of(
"from", "2026-05-01",
"to", "2026-05-31",
"granularity", "day"
));
System.out.println("Delivery rate: " + stats.summary().deliveryRate());
Error handling
import dev.sendry.*;
try {
sendry.emails.send(/* ... */);
} catch (AuthenticationException e) {
System.err.println("Bad API key: " + e.getMessage());
} catch (ValidationException e) {
System.err.println("Validation failed: " + e.getDetails());
} catch (RateLimitException e) {
// Back off and retry after e.getRetryAfter() seconds
Thread.sleep(e.getRetryAfter() == null ? 1000 : e.getRetryAfter() * 1000L);
} catch (NotFoundException e) {
System.err.println("Not found");
} catch (ApiException e) {
System.err.printf("API error %d (%s): %s%n",
e.getStatusCode(), e.getCode(), e.getMessage());
}
Webhook signature verification
Sendry signs every webhook payload using
HMAC-SHA256(secret, "${timestamp}.${body}") with the hex digest in the
x-sendry-signature header and the timestamp in x-sendry-timestamp.
import dev.sendry.WebhookVerifier;
// In your HTTP handler (Spring, Javalin, vanilla servlet, etc.):
String rawBody = readBody(request); // raw, unparsed
String sig = request.getHeader("x-sendry-signature");
long ts = Long.parseLong(request.getHeader("x-sendry-timestamp"));
String secret = System.getenv("SENDRY_WEBHOOK_SECRET");
if (!WebhookVerifier.verify(rawBody, sig, ts, secret)) {
response.setStatus(401);
return;
}
// Safe to process — request originated from Sendry.
Comparison is constant-time via MessageDigest.isEqual.
Source
github.com/sendry-dev/sendry-java —
Apache-2.0 licensed. Published to Maven Central as dev.sendry:sendry.