Skip to content

nuntly/nuntly-sdk-java

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

78 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nuntly-java

Maven Central License: MIT

The official Java 21 SDK for Nuntly, the developer-first email platform. Send transactional emails, manage domains, handle webhooks, and receive inbound mail with records, sealed interfaces, and pattern matching.

Documentation | API Reference | Website | Get your API key

Requires Java 21+. Uses records, sealed interfaces, pattern matching switch, and java.net.http.HttpClient.

Installation

Gradle (Kotlin DSL)

dependencies {
    implementation("com.nuntly:nuntly-java:0.0.1")
}

Gradle (Groovy)

dependencies {
    implementation 'com.nuntly:nuntly-java:0.0.1'
}

Maven

<dependency>
    <groupId>com.nuntly</groupId>
    <artifactId>nuntly-java</artifactId>
    <version>0.0.1</version>
</dependency>

Quick start

import com.nuntly.sdk.*;
import com.nuntly.sdk.models.*;
import java.util.List;

var nuntly = Nuntly.create(ClientOptions.builder()
    .apiKey(System.getenv("NUNTLY_API_KEY"))
    .build());

var email = nuntly.emails().send(CreateEmailRequest.builder()
    .from("hello@yourcompany.com")
    .to(List.of("recipient@example.com"))
    .subject("Welcome to Nuntly")
    .html("<h1>Welcome!</h1><p>Your account is ready.</p>")
    .build());

System.out.println(email.id());

Configuration

var nuntly = Nuntly.create(ClientOptions.builder()
    .apiKey(System.getenv("NUNTLY_API_KEY"))
    .baseUrl("https://api.nuntly.com")       // optional
    .timeout(Duration.ofSeconds(30))          // optional, default: 60s
    .maxRetries(3)                            // optional, default: 2
    .backoff(BackoffStrategy.builder()        // optional
        .initialIntervalMs(200)
        .maxIntervalMs(30000)
        .exponent(1.5)
        .build())
    .debug(true)                              // optional
    .build());

Pagination

// Auto-paginate all items
for (var item : nuntly.emails().list()) {
    System.out.println(item.id() + " - " + item.status());
}

// Stream API
nuntly.emails().list().stream()
    .filter(e -> "delivered".equals(e.status()))
    .forEach(e -> System.out.println(e.id()));

// Manual pagination
var page = nuntly.emails().list();
System.out.println(page.data());
if (page.hasNextPage()) {
    var next = page.nextPage();
}

Error handling

import com.nuntly.sdk.ApiError.*;

try {
    nuntly.emails().retrieve("em_invalid");
} catch (ApiError e) {
    switch (e) {
        case NotFoundError nf -> System.out.println("Not found: " + nf.requestId());
        case RateLimitError rl -> System.out.println("Retry in: " + rl.retryAfter() + "ms");
        case AuthenticationError ae -> System.out.println("Invalid API key");
        default -> System.out.println("HTTP " + e.status() + ": " + e.getMessage());
    }

    // Raw response access
    System.out.println(e.rawResponse().statusCode());
}

Lifecycle hooks

var nuntly = Nuntly.create(ClientOptions.builder()
    .apiKey(System.getenv("NUNTLY_API_KEY"))
    .hooks(Hooks.builder()
        .onRequest(req -> System.err.println("-> " + req.method() + " " + req.uri()))
        .onResponse((res, req) -> System.err.println("<- " + res.statusCode()))
        .onRetry(ctx -> System.err.println("Retry #" + ctx.attempt()))
        .onError((err, req) -> logger.error("Failed: " + req.uri(), err))
        .build())
    .build());

Raw response access

Inspect the underlying HTTP response on errors via ApiError.rawResponse():

try {
    nuntly.emails().retrieve("em_invalid");
} catch (ApiError e) {
    System.out.println(e.rawResponse().statusCode());
    System.out.println(e.rawResponse().headers().firstValue("x-request-id").orElse(""));
}

Spring Boot

A separate auto-configuration starter wires Nuntly as a bean and binds settings from application.yml / application.properties:

dependencies {
    implementation("com.nuntly:nuntly-java-spring:0.0.1")
}
# application.yml
nuntly:
  api-key: ${NUNTLY_API_KEY}
  base-url: https://api.nuntly.com  # optional
  timeout: 30s                       # optional
  max-retries: 3                     # optional
  debug: false                       # optional
@Service
public class MailService {
  private final Nuntly nuntly;

  public MailService(Nuntly nuntly) { this.nuntly = nuntly; }
}

Override any extensibility point by declaring a single @Bean. The starter wires it into the underlying ClientOptions:

@Bean Hooks hooks() {
  return Hooks.builder()
      .onRequest(req -> log.info("-> {} {}", req.method(), req.uri()))
      .build();
}

@Bean BackoffStrategy backoff() {
  return BackoffStrategy.builder().initialIntervalMs(200).build();
}

@Bean AppInfo appInfo() {
  return AppInfo.of("my-app", "1.4.2");
}

Webhook verification

Verify a webhook signature and parse the payload into a typed event:

import com.nuntly.sdk.lib.Webhook;
import com.nuntly.sdk.models.WebhookEvent;
import com.nuntly.sdk.models.WebhookEvent.*;

WebhookEvent event = Webhook.verify(payload, signatureHeader, secret);

switch (event) {
  case EmailBouncedEvent e -> handleBounce(e);
  case EmailDeliveredEvent e -> handleDelivered(e);
  case MessageReceivedEvent e -> handleReceive(e);
  default -> log.warn("Unhandled event type: {}", event.type());
}

WebhookEvent is a sealed interface; the compiler enforces exhaustive matching once every permitted subtype has a case.

Error types

NotFoundError, RateLimitError, AuthenticationError, PermissionDeniedError, ConflictError, BadRequestError, UnprocessableEntityError, InternalServerError. All extend ApiError. See ApiError.java.

License

MIT. See LICENSE.

About

The Nuntly Java SDK makes it easy to access the Nuntly REST API from Java.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages