Home
/
Blog
/
How to Send iMessages from Java / Spring Boot
March 29, 2026
8 min read
Nikita Jerschow

How to Send iMessages from Java / Spring Boot

Java developers can integrate iMessage into Spring Boot applications using the Sendblue REST API. This tutorial covers sending messages with both RestTemplate and WebClient, setting up webhook controllers, handling media attachments, and implementing async message sending with retry logic.

Prerequisites

You need:

  • Java 17+ and Spring Boot 3.x
  • Sendblue API credentialssign up free to get your API key and secret
  • Spring Web dependency for REST controllers and HTTP clients
  • Optionally, Spring WebFlux for reactive WebClient

Add the following to your application.properties:

sendblue.api.key=${SENDBLUE_API_KEY} sendblue.api.secret=${SENDBLUE_API_SECRET} sendblue.api.base-url=https://api.sendblue.co

Using RestTemplate

RestTemplate is the traditional way to make HTTP calls in Spring Boot. Here's a complete service class:

// src/main/java/com/example/service/SendblueService.java package com.example.service; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.util.*; @Service public class SendblueService { @Value("${sendblue.api.key}") private String apiKey; @Value("${sendblue.api.secret}") private String apiSecret; @Value("${sendblue.api.base-url}") private String baseUrl; private final RestTemplate restTemplate = new RestTemplate(); public Map<String, Object> sendMessage( String number, String content, String sendStyle, String mediaUrl) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("sb-api-key-id", apiKey); headers.set("sb-api-secret-key", apiSecret); Map<String, String> body = new HashMap<>(); body.put("number", number); body.put("content", content); if (sendStyle != null) body.put("send_style", sendStyle); if (mediaUrl != null) body.put("media_url", mediaUrl); HttpEntity<Map<String, String>> request = new HttpEntity<>(body, headers); ResponseEntity<Map> response = restTemplate.postForEntity( baseUrl + "/api/send-message", request, Map.class); return response.getBody(); } }

Use the service in a controller or anywhere Spring can inject it:

@Autowired private SendblueService sendblue; // Send a message sendblue.sendMessage("+15551234567", "Hello from Java!", "celebration", null);

Using WebClient (Reactive)

For non-blocking I/O in reactive Spring Boot applications, use WebClient:

// src/main/java/com/example/service/SendblueReactiveService.java package com.example.service; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; import java.util.*; @Service public class SendblueReactiveService { private final WebClient webClient; public SendblueReactiveService( @Value("${sendblue.api.key}") String apiKey, @Value("${sendblue.api.secret}") String apiSecret, @Value("${sendblue.api.base-url}") String baseUrl) { this.webClient = WebClient.builder() .baseUrl(baseUrl) .defaultHeader("sb-api-key-id", apiKey) .defaultHeader("sb-api-secret-key", apiSecret) .build(); } public Mono<Map> sendMessage(String number, String content) { Map<String, String> body = Map.of( "number", number, "content", content ); return webClient.post() .uri("/api/send-message") .bodyValue(body) .retrieve() .bodyToMono(Map.class); } public Mono<Map> evaluateService(String number) { return webClient.get() .uri(uriBuilder -> uriBuilder .path("/api/evaluate-service") .queryParam("number", number) .build()) .retrieve() .bodyToMono(Map.class); } }

WebClient is ideal for high-throughput applications where you need to send many messages concurrently without blocking threads.

Spring Boot Webhook Controller

Create a REST controller to handle incoming messages from Sendblue webhooks:

// src/main/java/com/example/controller/WebhookController.java package com.example.controller; import com.example.service.SendblueService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.Map; @RestController @RequestMapping("/webhooks") public class WebhookController { private static final Logger log = LoggerFactory.getLogger(WebhookController.class); @Autowired private SendblueService sendblue; @PostMapping("/receive") public ResponseEntity<Map<String, String>> receiveMessage( @RequestBody Map<String, Object> payload) { String fromNumber = (String) payload.get("from_number"); String content = (String) payload.get("content"); String mediaUrl = (String) payload.get("media_url"); String service = (String) payload.get("service"); log.info("[{}] {} : {}", service, fromNumber, content); // Process message (save to DB, trigger auto-reply, etc.) sendblue.sendMessage( fromNumber, "Thanks for your message! We'll respond shortly.", null, null ); return ResponseEntity.ok(Map.of("status", "ok")); } }

Configure your webhook URL in the Sendblue dashboard. For local development, use ngrok: ngrok http 8080.

Send Media Attachments

Attach images, videos, PDFs, or contact cards to any message:

// Send an image sendblue.sendMessage( "+15551234567", "Here's your report:", null, "https://example.com/report.pdf" ); // Send a contact card (vCard) — unique to Sendblue sendblue.sendMessage( "+15551234567", null, null, "https://example.com/sales-contact.vcf" );

Sendblue supports all file types. Contact card (.vcf) delivery is a unique feature — when recipients save the card, your business name appears on all future messages. This is powerful for sales outreach.

Async Message Sending with Retry

For production applications, send messages asynchronously with automatic retry logic:

import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; import org.springframework.scheduling.annotation.Async; @Service public class SendblueAsyncService { @Autowired private SendblueService sendblue; @Async @Retryable( maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 2) ) public void sendMessageAsync(String number, String content) { sendblue.sendMessage(number, content, null, null); } }

Enable async and retry in your Spring Boot application:

@SpringBootApplication @EnableAsync @EnableRetry public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

This pattern ensures reliable delivery without blocking your main application threads. Failed messages are automatically retried with exponential backoff.

Error Handling

Handle Sendblue API errors gracefully with a try-catch and structured logging:

public Map<String, Object> sendMessageSafe(String number, String content) { try { return sendMessage(number, content, null, null); } catch (HttpClientErrorException e) { log.error("Sendblue client error: {} - {}", e.getStatusCode(), e.getResponseBodyAsString()); return Map.of("error", e.getMessage()); } catch (HttpServerErrorException e) { log.error("Sendblue server error: {}", e.getStatusCode()); return Map.of("error", "Server error, will retry"); } catch (Exception e) { log.error("Unexpected error sending iMessage", e); return Map.of("error", e.getMessage()); } }

Common error codes: 400 (invalid phone number or missing fields), 401 (invalid API credentials), 429 (rate limited). See the API documentation for the complete error reference.

Next Steps

You're now sending iMessages from Java and Spring Boot. Continue with:

Get your free API keys and start sending iMessages from Java today.

Ready to send your first iMessage?

Get API access in minutes. Free sandbox, no credit card required.

Get API Access