Documentation

Java SDK

Java 21+
Maven

Send emails with Java using the official Laneful Java SDK. Built for modern Java applications with comprehensive features and type safety.

Full Feature Support

Templates, attachments, tracking, webhooks

Type Safe

Built-in validation & error handling

Modern Java

Java 21+ with builder pattern

Prerequisites

To get the most out of this guide, you'll need:

  • • Java 21 or higher
  • • Maven 3.6+
  • • A Laneful account with API key
  • • Verified domain for sending emails

Installation

Maven

Add the following dependency to your pom.xml:

<dependency>
    <groupId>com.laneful</groupId>
    <artifactId>laneful-java</artifactId>
    <version>1.1.0</version>
</dependency>

Quick Start

Send your first email in minutes:

Send Simple Text Email

import com.laneful.client.LanefulClient;
import com.laneful.models.Email;
import com.laneful.models.Address;
import com.laneful.exceptions.*;

public class Main {
    public static void main(String[] args) {
        // Create client
        LanefulClient client = new LanefulClient(
            "https://your-endpoint.send.laneful.net",
            "your-auth-token"
        );

        // Create email
        Email email = new Email.Builder()
            .from(new Address("sender@example.com", "Your Name"))
            .to(new Address("recipient@example.com", "Recipient Name"))
            .subject("Hello from Laneful!")
            .textContent("This is a simple test email sent using the Laneful Java SDK.")
            .build();

        // Send email
        try {
            Map<String, Object> response = client.sendEmail(email);
            System.out.println("✓ Email sent successfully!");
            System.out.println("Response: " + response);
        } catch (ValidationException e) {
            System.err.println("✗ Validation error: " + e.getMessage());
        } catch (ApiException e) {
            System.err.println("✗ API error: " + e.getMessage());
            System.err.println("Status code: " + e.getStatusCode());
        } catch (HttpException e) {
            System.err.println("✗ HTTP error: " + e.getMessage());
        } catch (Exception e) {
            System.err.println("✗ Unexpected error: " + e.getMessage());
        }
    }
}

Examples

Common use cases and patterns:

HTML Email with Tracking

import com.laneful.models.TrackingSettings;

// Create tracking settings
TrackingSettings tracking = new TrackingSettings(true, true, true);

Email email = new Email.Builder()
    .from(new Address("sender@example.com", "Your Name"))
    .to(new Address("recipient@example.com", "Recipient Name"))
    .subject("HTML Email with Tracking")
    .htmlContent("<h1>Welcome!</h1><p>This is an <strong>HTML email</strong> with tracking enabled.</p>")
    .textContent("Welcome! This is an HTML email with tracking enabled.")
    .tracking(tracking)
    .tag("welcome-email")
    .build();

Map<String, Object> response = client.sendEmail(email);

Template Email

Email email = new Email.Builder()
    .from(new Address("sender@example.com"))
    .to(new Address("user@example.com"))
    .templateId("welcome-template")
    .templateData(Map.of(
        "name", "John Doe",
        "company", "Acme Corporation",
        "activation_link", "https://example.com/activate"
    ))
    .build();

Map<String, Object> response = client.sendEmail(email);

Email with Attachments

import com.laneful.models.Attachment;
import java.nio.file.Paths;

// Create attachment from file
Attachment attachment = Attachment.fromFile(Paths.get("/path/to/document.pdf"));

Email email = new Email.Builder()
    .from(new Address("sender@example.com"))
    .to(new Address("user@example.com"))
    .subject("Document Attached")
    .textContent("Please find the document attached.")
    .attachment(attachment)
    .build();

Map<String, Object> response = client.sendEmail(email);

Multiple Recipients with Reply-To

Email email = new Email.Builder()
    .from(new Address("sender@example.com", "Your Name"))
    .to(new Address("user1@example.com", "User One"))
    .to(new Address("user2@example.com", "User Two"))
    .cc(new Address("cc@example.com", "CC Recipient"))
    .bcc(new Address("bcc@example.com", "BCC Recipient"))
    .replyTo(new Address("reply@example.com", "Reply To"))
    .subject("Email to Multiple Recipients")
    .textContent("This email is being sent to multiple recipients.")
    .build();

Map<String, Object> response = client.sendEmail(email);

Scheduled Email

import java.time.Instant;

// Schedule for 24 hours from now
long sendTime = Instant.now().plusSeconds(24 * 60 * 60).getEpochSecond();

Email email = new Email.Builder()
    .from(new Address("sender@example.com"))
    .to(new Address("user@example.com"))
    .subject("Scheduled Email")
    .textContent("This email was scheduled.")
    .sendTime(sendTime)
    .build();

Map<String, Object> response = client.sendEmail(email);

Batch Email Sending

List<Email> emails = List.of(
    new Email.Builder()
        .from(new Address("sender@example.com"))
        .to(new Address("user1@example.com"))
        .subject("Email 1")
        .textContent("First email content.")
        .build(),
    new Email.Builder()
        .from(new Address("sender@example.com"))
        .to(new Address("user2@example.com"))
        .subject("Email 2")
        .textContent("Second email content.")
        .build()
);

Map<String, Object> response = client.sendEmails(emails);

Webhook Handler Example

import com.laneful.webhooks.WebhookVerifier;
import java.util.Map;

// Complete webhook handler implementation
@PostMapping("/webhook")
public ResponseEntity<String> handleWebhook(
    @RequestBody String payload,
    @RequestHeader Map<String, String> headers) {
    
    try {
        // Extract signature from headers
        String signature = WebhookVerifier.extractSignatureFromHeaders(headers);
        if (signature == null) {
            return ResponseEntity.status(401).body("Missing signature");
        }
        
        // Verify signature
        if (!WebhookVerifier.verifySignature(webhookSecret, payload, signature)) {
            return ResponseEntity.status(401).body("Invalid signature");
        }
        
        // Parse and validate payload
        WebhookVerifier.WebhookData webhookData = WebhookVerifier.parseWebhookPayload(payload);
        
        // Process events
        for (Map<String, Object> event : webhookData.getEvents()) {
            String eventType = (String) event.get("event");
            String email = (String) event.get("email");
            
            switch (eventType) {
                case "delivery":
                    logger.info("Email delivered to: " + email);
                    break;
                case "open":
                    logger.info("Email opened by: " + email);
                    break;
                case "click":
                    String url = (String) event.get("url");
                    logger.info("Link clicked by " + email + ": " + url);
                    break;
                case "bounce":
                    Boolean isHard = (Boolean) event.get("is_hard");
                    logger.info("Email bounced (" + (isHard ? "hard" : "soft") + ") for: " + email);
                    break;
            }
        }
        
        return ResponseEntity.ok("Webhook processed successfully");
        
    } catch (IllegalArgumentException e) {
        return ResponseEntity.status(400).body("Invalid payload: " + e.getMessage());
    } catch (Exception e) {
        return ResponseEntity.status(500).body("Processing error: " + e.getMessage());
    }
}

API Reference

LanefulClient

Constructors

  • LanefulClient(String baseUrl, String authToken) - Default timeout (30 seconds)
  • LanefulClient(String baseUrl, String authToken, Duration timeout) - Custom timeout
  • LanefulClient(String baseUrl, String authToken, Duration timeout, OkHttpClient httpClient) - Custom HTTP client

Methods

  • Map<String, Object> sendEmail(Email email) - Send single email
  • Map<String, Object> sendEmails(List<Email> emails) - Send multiple emails

Email.Builder

Required Fields

  • from(Address from) - Sender address

Optional Fields

  • to(Address to) - Recipient addresses
  • cc(Address cc) - CC recipient addresses
  • bcc(Address bcc) - BCC recipient addresses
  • replyTo(Address replyTo) - Reply-to address
  • subject(String subject) - Email subject
  • textContent(String textContent) - Plain text content
  • htmlContent(String htmlContent) - HTML content
  • templateId(String templateId) - Template ID
  • templateData(Map<String, Object> templateData) - Template data
  • attachment(Attachment attachment) - File attachments
  • sendTime(Long sendTime) - Scheduled send time
  • tracking(TrackingSettings tracking) - Email tracking configuration
  • tag(String tag) - Email tag for categorization

Utility Classes

  • Address(String email, String name) - Email address with optional name
  • Attachment.fromFile(Path path) - Create attachment from file
  • TrackingSettings(boolean opens, boolean clicks, boolean unsubscribes) - Email tracking configuration (opens, clicks, unsubscribes)

WebhookVerifier

Signature Verification

  • boolean verifySignature(String secret, String payload, String signature) - Verifies webhook signature (supports sha256= prefix)
  • String generateSignature(String secret, String payload) - Generates signature for payload
  • String generateSignature(String secret, String payload, boolean includePrefix) - Generates signature with optional prefix

Payload Processing

  • WebhookData parseWebhookPayload(String payload) - Parse and validate webhook payload structure
  • String getSignatureHeaderName() - Get the correct header name for webhook signatures
  • String extractSignatureFromHeaders(Map<String, String> headers) - Extract signature from HTTP headers

WebhookData

  • boolean isBatch() - Returns true if payload contains multiple events
  • List<Map<String, Object>> getEvents() - Returns list of parsed events

Error Handling

Comprehensive error handling with specific exception types:

import com.laneful.exceptions.*;

try {
    Map<String, Object> response = client.sendEmail(email);
    System.out.println("✓ Email sent successfully!");
    System.out.println("Response: " + response);
} catch (ValidationException e) {
    // Invalid input data
    System.err.println("✗ Validation error: " + e.getMessage());
    System.err.println("Please check your email configuration");
} catch (ApiException e) {
    // API returned an error
    System.err.println("✗ API error: " + e.getMessage());
    System.err.println("  Status code: " + e.getStatusCode());
    System.err.println("  Error message: " + e.getErrorMessage());
    System.err.println("Please check your API credentials and endpoint");
} catch (HttpException e) {
    // Network or HTTP-level error
    System.err.println("✗ HTTP error: " + e.getMessage());
    System.err.println("  Status code: " + e.getStatusCode());
    System.err.println("Please check your network connection and endpoint URL");
} catch (Exception e) {
    // Other unexpected errors
    System.err.println("✗ Unexpected error: " + e.getMessage());
    e.printStackTrace();
}

Exception Types

  • ValidationException - Input validation fails
  • ApiException - API returns error response
    Methods: getStatusCode(), getErrorMessage()
  • HttpException - HTTP communication fails
    Methods: getStatusCode()
  • LanefulException - Base exception class

Best Practices

  • • Always wrap API calls in try-catch
  • • Handle specific exception types first
  • • Log errors with context information
  • • Implement retry logic for transient failures

Webhook Handling

Comprehensive webhook handling with signature verification, payload parsing, and validation:

Basic Signature Verification

import com.laneful.webhooks.WebhookVerifier;

// In your webhook handler
String payload = request.getBody(); // Get the raw request body
String signature = request.getHeader("x-webhook-signature");
String secret = "your-webhook-secret";

if (WebhookVerifier.verifySignature(secret, payload, signature)) {
    // Process webhook data
    WebhookVerifier.WebhookData webhookData = WebhookVerifier.parseWebhookPayload(payload);
    // Handle webhook events
} else {
    // Invalid signature
    response.setStatus(401);
}

Advanced Webhook Processing

import com.laneful.webhooks.WebhookVerifier;
import java.util.Map;

// Complete webhook verification and processing workflow
try {
    // Step 1: Get raw payload
    String payload = request.getBody();
    
    // Step 2: Extract signature from headers (supports multiple formats)
    String signature = WebhookVerifier.extractSignatureFromHeaders(getHeaders(request));
    
    // Step 3: Verify signature (supports sha256= prefix)
    if (!WebhookVerifier.verifySignature(webhookSecret, payload, signature)) {
        throw new SecurityException("Invalid webhook signature");
    }
    
    // Step 4: Parse and validate payload structure
    WebhookVerifier.WebhookData webhookData = WebhookVerifier.parseWebhookPayload(payload);
    
    // Step 5: Process events (handles both batch and single event formats)
    for (Map<String, Object> event : webhookData.getEvents()) {
        String eventType = (String) event.get("event");
        String email = (String) event.get("email");
        
        switch (eventType) {
            case "delivery":
                handleDeliveryEvent(event);
                break;
            case "open":
                handleOpenEvent(event);
                break;
            case "click":
                handleClickEvent(event);
                break;
            case "bounce":
                handleBounceEvent(event);
                break;
            case "drop":
                handleDropEvent(event);
                break;
            case "spam_complaint":
                handleSpamComplaintEvent(event);
                break;
            case "unsubscribe":
                handleUnsubscribeEvent(event);
                break;
        }
    }
    
} catch (IllegalArgumentException e) {
    // Payload validation error
    response.setStatus(400);
} catch (Exception e) {
    // Other errors
    response.setStatus(401);
}

Batch Mode Support

WebhookVerifier.WebhookData webhookData = WebhookVerifier.parseWebhookPayload(payload);

if (webhookData.isBatch()) {
    // Processing multiple events in batch mode
    System.out.println("Processing " + webhookData.getEvents().size() + " events in batch");
} else {
    // Processing single event
    System.out.println("Processing single event");
}

// Process all events
for (Map<String, Object> event : webhookData.getEvents()) {
    processEvent(event);
}

Supported Webhook Events

Delivery Events

  • delivery - Email delivered successfully
  • bounce - Email bounced (hard or soft)
  • drop - Email dropped (spam, invalid, etc.)
  • spam_complaint - Recipient marked email as spam

Engagement Events

  • open - Email opened by recipient
  • click - Link clicked in email
  • unsubscribe - Recipient unsubscribed

Webhook Features

Security

  • • HMAC-SHA256 signature verification
  • • Support for sha256= prefix
  • • Constant-time comparison (timing attack protection)
  • • Multiple header format support

Validation

  • • JSON payload structure validation
  • • Required field validation
  • • Event type validation
  • • Email format validation
  • • UUID format validation for lane_id

Ready to Get Started?

Start sending emails with Java in minutes. Check out the examples and integrate with your application.