Java SDK

Enterprise Java SDK with Maven/Gradle support, Spring Boot integration, and Android compatibility.

✅ Ready v1.0.0 Maven/Gradle

Quick Start

Maven Installation

<dependency>
    <groupId>com.sparkmailr</groupId>
    <artifactId>sparkmailr-java-sdk</artifactId>
    <version>1.0.0</version>
</dependency>

Gradle Installation

implementation 'com.sparkmailr:sparkmailr-java-sdk:1.0.0'

Basic Usage

import com.sparkmailr.SparkMailrClient;
import com.sparkmailr.model.SendEmailRequest;
import com.sparkmailr.model.EmailResponse;
import com.sparkmailr.exceptions.SparkMailrException;

import java.util.Arrays;

public class EmailExample {
    public static void main(String[] args) {
        // Initialize client
        SparkMailrClient client = new SparkMailrClient.Builder()
            .apiKey("your-api-key")
            .build();
        
        try {
            // Send email
            SendEmailRequest request = new SendEmailRequest.Builder()
                .to(Arrays.asList("user@example.com"))
                .from("noreply@yourapp.com")
                .subject("Welcome to SparkMailr!")
                .html("<h1>Hello World</h1>")
                .text("Hello World")
                .build();
            
            EmailResponse response = client.emails().send(request);
            System.out.println("Email sent: " + response.getId());
            
        } catch (SparkMailrException e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

Configuration

import com.sparkmailr.SparkMailrClient;
import com.sparkmailr.SparkMailrConfig;
import java.time.Duration;

// Full configuration using Builder pattern
SparkMailrClient client = new SparkMailrClient.Builder()
    .apiKey("your-api-key")
    .baseUrl("https://api.sparkmailr.com")  // Optional
    .timeout(Duration.ofSeconds(30))        // Request timeout
    .maxRetries(3)                          // Max retry attempts
    .retryDelay(Duration.ofSeconds(1))      // Delay between retries
    .debug(false)                           // Enable debug logging
    .build();

// Configuration from properties
SparkMailrConfig config = SparkMailrConfig.builder()
    .apiKey(System.getProperty("sparkmailr.api.key"))
    .baseUrl(System.getProperty("sparkmailr.base.url"))
    .timeout(Duration.ofSeconds(
        Integer.parseInt(System.getProperty("sparkmailr.timeout", "30"))
    ))
    .build();

SparkMailrClient client = new SparkMailrClient(config);

Spring Boot Integration

Configuration Properties

# application.yml
sparkmailr:
  api-key: ${SPARKMAILR_API_KEY}
  base-url: https://api.sparkmailr.com
  timeout: 30000
  max-retries: 3
  debug: ${spring.profiles.active:} == 'dev'

Configuration Class

@Configuration
@ConfigurationProperties(prefix = "sparkmailr")
@Data
public class SparkMailrProperties {
    private String apiKey;
    private String baseUrl = "https://api.sparkmailr.com";
    private int timeout = 30000;
    private int maxRetries = 3;
    private boolean debug = false;
}

@Configuration
@EnableConfigurationProperties(SparkMailrProperties.class)
public class SparkMailrConfig {
    
    @Bean
    public SparkMailrClient sparkMailrClient(SparkMailrProperties properties) {
        return new SparkMailrClient.Builder()
            .apiKey(properties.getApiKey())
            .baseUrl(properties.getBaseUrl())
            .timeout(Duration.ofMillis(properties.getTimeout()))
            .maxRetries(properties.getMaxRetries())
            .debug(properties.isDebug())
            .build();
    }
}

Service Implementation

@Service
@Slf4j
public class EmailService {
    
    private final SparkMailrClient sparkMailrClient;
    
    public EmailService(SparkMailrClient sparkMailrClient) {
        this.sparkMailrClient = sparkMailrClient;
    }
    
    public String sendWelcomeEmail(String userEmail, String userName) {
        try {
            Map<String, Object> templateData = Map.of(
                "name", userName,
                "activationLink", "https://app.example.com/activate",
                "supportEmail", "support@yourapp.com"
            );
            
            SendEmailRequest request = new SendEmailRequest.Builder()
                .to(List.of(userEmail))
                .from("noreply@yourapp.com")
                .templateId("welcome-template")
                .templateData(templateData)
                .build();
            
            EmailResponse response = sparkMailrClient.emails().send(request);
            log.info("Welcome email sent to {}: {}", userEmail, response.getId());
            return response.getId();
            
        } catch (SparkMailrException e) {
            log.error("Failed to send welcome email to {}: {}", userEmail, e.getMessage());
            throw new EmailServiceException("Failed to send welcome email", e);
        }
    }
    
    @Async
    public CompletableFuture<String> sendWelcomeEmailAsync(String userEmail, String userName) {
        return CompletableFuture.supplyAsync(() -> sendWelcomeEmail(userEmail, userName));
    }
}

REST Controller

@RestController
@RequestMapping("/api/emails")
@Validated
public class EmailController {
    
    private final EmailService emailService;
    
    public EmailController(EmailService emailService) {
        this.emailService = emailService;
    }
    
    @PostMapping("/send-welcome")
    public ResponseEntity<Map<String, String>> sendWelcomeEmail(
            @Valid @RequestBody SendWelcomeRequest request) {
        
        try {
            String emailId = emailService.sendWelcomeEmail(
                request.getEmail(), 
                request.getName()
            );
            
            return ResponseEntity.ok(Map.of(
                "success", "true",
                "emailId", emailId
            ));
            
        } catch (EmailServiceException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(Map.of(
                    "success", "false",
                    "error", e.getMessage()
                ));
        }
    }
    
    @PostMapping("/send-bulk")
    public ResponseEntity<Map<String, Object>> sendBulkEmails(
            @Valid @RequestBody BulkEmailRequest request) {
        
        List<BulkEmailRecipient> recipients = request.getEmails().stream()
            .map(email -> new BulkEmailRecipient.Builder()
                .to(email.getTo())
                .templateData(email.getTemplateData())
                .build())
            .collect(Collectors.toList());
        
        com.sparkmailr.model.BulkEmailRequest bulkRequest = 
            new com.sparkmailr.model.BulkEmailRequest.Builder()
                .from(request.getFrom())
                .templateId(request.getTemplateId())
                .recipients(recipients)
                .build();
        
        BulkEmailResponse response = sparkMailrClient.emails().sendBulk(bulkRequest);
        
        return ResponseEntity.ok(Map.of(
            "success", true,
            "batchId", response.getBatchId(),
            "count", recipients.size()
        ));
    }
}

Advanced Features

Template Emails

// Send email with template and complex data
Map<String, Object> templateData = new HashMap<>();
templateData.put("user", Map.of(
    "firstName", "John",
    "lastName", "Doe",
    "plan", "premium"
));
templateData.put("features", Arrays.asList("Feature 1", "Feature 2", "Feature 3"));
templateData.put("activationLink", "https://app.example.com/activate/123");
templateData.put("expirationDate", "2025-02-15");

SendEmailRequest request = new SendEmailRequest.Builder()
    .to(Arrays.asList("user@example.com"))
    .from("noreply@yourapp.com")
    .templateId("welcome-template")
    .templateData(templateData)
    .build();

EmailResponse response = client.emails().send(request);
System.out.println("Template email sent: " + response.getId());

Bulk Email Sending

// Prepare bulk recipients
List<BulkEmailRecipient> recipients = Arrays.asList(
    new BulkEmailRecipient.Builder()
        .to("user1@example.com")
        .templateData(Map.of("name", "User 1", "code", "ABC123"))
        .build(),
    new BulkEmailRecipient.Builder()
        .to("user2@example.com")
        .templateData(Map.of("name", "User 2", "code", "DEF456"))
        .build(),
    new BulkEmailRecipient.Builder()
        .to("user3@example.com")
        .templateData(Map.of("name", "User 3", "code", "GHI789"))
        .build()
);

BulkEmailRequest bulkRequest = new BulkEmailRequest.Builder()
    .from("newsletter@yourapp.com")
    .templateId("newsletter-template")
    .recipients(recipients)
    .build();

BulkEmailResponse response = client.emails().sendBulk(bulkRequest);
System.out.println("Bulk batch: " + response.getBatchId());

Email Status & Analytics

// Get email status
String emailId = "em_1234567890";
EmailStatus status = client.emails().getStatus(emailId);

System.out.println("Status: " + status.getStatus());
System.out.println("Delivered: " + status.getDeliveredAt());
System.out.println("Opened: " + status.getOpenedAt());

// Get analytics
AnalyticsRequest analyticsRequest = new AnalyticsRequest.Builder()
    .startDate(LocalDate.of(2025, 1, 1))
    .endDate(LocalDate.of(2025, 1, 31))
    .build();

EmailAnalytics analytics = client.analytics().getEmailStats(analyticsRequest);

System.out.println("Total sent: " + analytics.getSent());
System.out.println("Delivery rate: " + analytics.getDeliveryRate() + "%");
System.out.println("Open rate: " + analytics.getOpenRate() + "%");
System.out.println("Click rate: " + analytics.getClickRate() + "%");

Error Handling

import com.sparkmailr.exceptions.*;

try {
    SendEmailRequest request = new SendEmailRequest.Builder()
        .to(Arrays.asList("invalid-email"))
        .from("noreply@yourapp.com")
        .subject("Test Email")
        .build();
    
    EmailResponse response = client.emails().send(request);
    
} catch (AuthenticationException e) {
    System.err.println("Authentication failed - check API key: " + e.getMessage());
} catch (RateLimitException e) {
    System.err.println("Rate limited - retry after: " + e.getRetryAfter() + " seconds");
    // Implement exponential backoff
    try {
        Thread.sleep(e.getRetryAfter() * 1000);
        // Retry logic here
    } catch (InterruptedException ie) {
        Thread.currentThread().interrupt();
    }
} catch (ValidationException e) {
    System.err.println("Validation failed:");
    e.getValidationErrors().forEach((field, errors) -> 
        System.err.println("  " + field + ": " + String.join(", ", errors))
    );
} catch (NetworkException e) {
    System.err.println("Network error: " + e.getMessage());
} catch (SparkMailrException e) {
    System.err.println("SparkMailr error: " + e.getMessage());
} catch (Exception e) {
    System.err.println("Unexpected error: " + e.getMessage());
}

Android Integration

// build.gradle (Module: app)
dependencies {
    implementation 'com.sparkmailr:sparkmailr-java-sdk:1.0.0'
    implementation 'com.squareup.okhttp3:okhttp:4.12.0'
}

// EmailService.java
public class EmailService {
    private static final String TAG = "EmailService";
    private SparkMailrClient client;
    
    public EmailService(String apiKey) {
        this.client = new SparkMailrClient.Builder()
            .apiKey(apiKey)
            .timeout(Duration.ofSeconds(30))
            .build();
    }
    
    public void sendContactEmail(String name, String email, String message, 
                               EmailCallback callback) {
        // Use AsyncTask or modern alternatives like ExecutorService
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Handler mainHandler = new Handler(Looper.getMainLooper());
        
        executor.execute(() -> {
            try {
                SendEmailRequest request = new SendEmailRequest.Builder()
                    .to(Arrays.asList("support@yourapp.com"))
                    .from("noreply@yourapp.com")
                    .subject("Contact Form from " + name)
                    .html("<h2>Contact Form</h2>" +
                          "<p><strong>Name:</strong> " + name + "</p>" +
                          "<p><strong>Email:</strong> " + email + "</p>" +
                          "<p><strong>Message:</strong></p>" +
                          "<p>" + message + "</p>")
                    .build();
                
                EmailResponse response = client.emails().send(request);
                
                mainHandler.post(() -> callback.onSuccess(response.getId()));
                
            } catch (SparkMailrException e) {
                Log.e(TAG, "Failed to send email", e);
                mainHandler.post(() -> callback.onError(e.getMessage()));
            }
        });
    }
    
    public interface EmailCallback {
        void onSuccess(String emailId);
        void onError(String error);
    }
}

// Usage in Activity
public class ContactActivity extends AppCompatActivity {
    private EmailService emailService;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_contact);
        
        emailService = new EmailService(getString(R.string.sparkmailr_api_key));
        
        Button sendButton = findViewById(R.id.send_button);
        sendButton.setOnClickListener(v -> sendContactForm());
    }
    
    private void sendContactForm() {
        EditText nameField = findViewById(R.id.name_field);
        EditText emailField = findViewById(R.id.email_field);
        EditText messageField = findViewById(R.id.message_field);
        
        emailService.sendContactEmail(
            nameField.getText().toString(),
            emailField.getText().toString(),
            messageField.getText().toString(),
            new EmailService.EmailCallback() {
                @Override
                public void onSuccess(String emailId) {
                    Toast.makeText(ContactActivity.this, 
                        "Message sent successfully!", Toast.LENGTH_SHORT).show();
                }
                
                @Override
                public void onError(String error) {
                    Toast.makeText(ContactActivity.this, 
                        "Failed to send message: " + error, Toast.LENGTH_LONG).show();
                }
            }
        );
    }
}

Testing with JUnit

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

public class SparkMailrClientTest {
    
    @Mock
    private SparkMailrClient mockClient;
    
    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
    }
    
    @Test
    void testSendEmailSuccess() throws SparkMailrException {
        // Arrange
        SendEmailRequest request = new SendEmailRequest.Builder()
            .to(Arrays.asList("test@example.com"))
            .from("noreply@test.com")
            .subject("Test Email")
            .html("<p>Test content</p>")
            .build();
        
        EmailResponse expectedResponse = new EmailResponse("em_123456", "queued");
        when(mockClient.emails().send(request)).thenReturn(expectedResponse);
        
        // Act
        EmailResponse response = mockClient.emails().send(request);
        
        // Assert
        assertEquals("em_123456", response.getId());
        assertEquals("queued", response.getStatus());
        verify(mockClient.emails()).send(request);
    }
    
    @Test
    void testRateLimitException() throws SparkMailrException {
        // Arrange
        SendEmailRequest request = new SendEmailRequest.Builder()
            .to(Arrays.asList("test@example.com"))
            .from("noreply@test.com")
            .subject("Test")
            .build();
        
        RateLimitException exception = new RateLimitException("Rate limit exceeded", 60);
        when(mockClient.emails().send(request)).thenThrow(exception);
        
        // Act & Assert
        RateLimitException thrown = assertThrows(RateLimitException.class, () -> {
            mockClient.emails().send(request);
        });
        
        assertEquals(60, thrown.getRetryAfter());
        assertEquals("Rate limit exceeded", thrown.getMessage());
    }
}

// Integration test with WireMock
@ExtendWith(WireMockExtension.class)
public class SparkMailrIntegrationTest {
    
    @Test
    void testSendEmailIntegration(WireMockRuntimeInfo wmRuntimeInfo) {
        // Setup WireMock
        WireMock.stubFor(WireMock.post(WireMock.urlEqualTo("/v1/emails/send"))
            .willReturn(WireMock.aResponse()
                .withStatus(200)
                .withHeader("Content-Type", "application/json")
                .withBody("{\"id\":\"em_123456\",\"status\":\"queued\"}")));
        
        // Create client with WireMock URL
        SparkMailrClient client = new SparkMailrClient.Builder()
            .apiKey("test-key")
            .baseUrl(wmRuntimeInfo.getHttpBaseUrl())
            .build();
        
        // Send email
        SendEmailRequest request = new SendEmailRequest.Builder()
            .to(Arrays.asList("test@example.com"))
            .from("noreply@test.com")
            .subject("Integration Test")
            .html("<p>Test content</p>")
            .build();
        
        EmailResponse response = client.emails().send(request);
        
        // Verify
        assertEquals("em_123456", response.getId());
        assertEquals("queued", response.getStatus());
    }
}

Need More Help?

Complete Documentation Maven Central Contact Support