Skip to content

Send emails with Java

Learn how to send transactional emails using PostStack and Java.

Java 11 introduced `java.net.http.HttpClient` as a first-class HTTP client in the stdlib, removing the need for Apache HttpClient, OkHttp, or RestTemplate for simple REST integrations. PostStack accepts a small JSON POST with Bearer auth, so the stdlib client is plenty. For Spring Boot apps, integrating via `JavaMailSender` and SMTP is usually cleaner so `@Async` and `@Retryable` annotations Just Work.

1. Install the SDK

bash
// No external dependencies uses Java 11+ HttpClient

2. Initialize the client

java
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;

HttpClient client = HttpClient.newHttpClient();
String apiKey = System.getenv("POSTSTACK_API_KEY");

3. Send an email

java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class SendEmail {
    public static void main(String[] args) throws Exception {
        String apiKey = System.getenv("POSTSTACK_API_KEY");

        String json = """
            {
                "from": "hello@yourdomain.com",
                "to": ["user@example.com"],
                "subject": "Hello from Java!",
                "html": "<h1>Welcome!</h1>"
            }
            """;

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.poststack.dev/emails"))
            .header("Authorization", "Bearer " + apiKey)
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(json))
            .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());

        System.out.println(response.body());
    }
}

4. Handle errors

Java idioms for error handling, retries, and structured logging when calling the PostStack API.

java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class PoststackClient {
    private static final HttpClient HTTP = HttpClient.newBuilder()
        .connectTimeout(Duration.ofSeconds(5))
        .build();

    public static String send(String json) throws Exception {
        for (int attempt = 0; attempt < 3; attempt++) {
            HttpRequest req = HttpRequest.newBuilder()
                .uri(URI.create("https://api.poststack.dev/emails"))
                .header("Authorization", "Bearer " + System.getenv("POSTSTACK_API_KEY"))
                .header("Content-Type", "application/json")
                .timeout(Duration.ofSeconds(10))
                .POST(HttpRequest.BodyPublishers.ofString(json))
                .build();

            HttpResponse<String> res = HTTP.send(req, HttpResponse.BodyHandlers.ofString());

            if (res.statusCode() >= 200 && res.statusCode() < 300) {
                return res.body();
            }
            if (res.statusCode() == 429 || res.statusCode() >= 500) {
                Thread.sleep((long) Math.pow(2, attempt) * 1000);
                continue;
            }
            throw new RuntimeException("PostStack " + res.statusCode() + ": " + res.body());
        }
        throw new RuntimeException("PostStack: retries exhausted");
    }
}

Framework integrations

Spring Boot — JavaMailSender + SMTP

In `application.yml`, set `spring.mail.host: smtp.poststack.dev`, `port: 587`, `username: poststack`, `password: ${POSTSTACK_API_KEY}`, `properties.mail.smtp.starttls.enable: true`. Inject `JavaMailSender` into your services and use `@Async` to make sends non-blocking.

Spring Boot — WebClient

For non-blocking REST calls, use Spring WebFlux’s `WebClient`. Configure a `@Bean` with the API key on construction, then `webClient.post().uri("/emails").bodyValue(payload).retrieve().bodyToMono(EmailResponse.class)`. Pair with `Resilience4j` for retry policies.

Quarkus / Micronaut

Both frameworks have first-class declarative HTTP clients. Define a `@RegisterRestClient` (Quarkus) or `@Client` (Micronaut) interface with the PostStack endpoint, then inject and call. CDI handles the singleton lifetime.

Plain JVM apps

For non-Spring apps, build an `HttpClient` singleton at startup and share it across threads. The Java stdlib `HttpClient` is thread-safe and pools connections internally.

Common pitfalls

  • Creating a new HttpClient per request

    `HttpClient.newHttpClient()` spins up an internal executor and connection pool — recreating it per request leaks threads. Cache a single instance at class level or via DI.

  • Forgetting `.timeout(...)`

    Without `.connectTimeout()` and `.timeout()`, a stuck connection blocks the calling thread indefinitely. Always set both — 5 seconds connect, 10 seconds total is a reasonable default.

  • Mixing `send()` and `sendAsync()`

    `HttpClient.send` blocks; `sendAsync` returns `CompletableFuture`. Don’t call `.get()` on the future inside a blocking handler — it just adds context-switch overhead. Pick one model and stay consistent.

Notes

  • Uses the Java 11+ built-in HttpClient — no Maven/Gradle dependencies needed

FAQ

Do I need Apache HttpClient or OkHttp?

No. Java 11+ has a stdlib HttpClient that is more than enough for PostStack’s REST API. Skip the extra dependency.

How do I integrate with Spring Boot?

For SMTP, configure JavaMailSender via `application.yml`. For REST, define a `WebClient` bean or use the stdlib `HttpClient` directly. Both are detailed in the integrations section.

Is `HttpClient` thread-safe?

Yes. A single `HttpClient` instance is thread-safe and pools connections internally. Share one instance across your application.

Related guides

Ready to send emails with Java?

Create a free account and get your API key in under a minute.