
Send SMS from Java: No Twilio, Just Your Android Phone
Send real SMS from Java using textbee and your Android phone as the gateway. Native HttpClient, OkHttp, and Spring Boot examples, zero per-message fees.
TL;DR
- textbee's REST API works from any Java version with HTTP capability: no SDK or Twilio account needed.
- Three options: native
HttpClient(Java 11+, zero dependencies), OkHttp (Maven/Gradle), or Spring BootRestTemplate. - Store credentials in environment variables, not hardcoded strings.
- The
recipientsfield is a JSON array: one request sends to multiple numbers. - No per-message API fee: messages route through the SIM in your Android phone.
You don't need a Twilio account or a rented virtual number to send SMS from Java. If you have an Android phone with a working SIM, textbee turns it into an SMS gateway your Java code can call over a plain REST API. The message goes out from your real phone number.
Before you start
- textbee app installed on your Android device and linked to your account: download and quickstart
- Device ID and API key from the dashboard at textbee.dev
- Java 11+ for the native
HttpClientexample; Java 8+ for OkHttp - On Android 15 or 16? You may need to manually enable SMS permissions once
Option 1: Native HttpClient (Java 11+, no dependencies)
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 TextbeeSender {
private static final HttpClient CLIENT = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
public static String sendSms(String to, String message) throws Exception {
String apiKey = System.getenv("TEXTBEE_API_KEY");
String url = "https://api.textbee.dev/api/v1/gateway/send-sms";
String body = String.format(
"{\"recipients\": [\"%s\"], \"message\": \"%s\"}",
to, message.replace("\"", "\\\"")
);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.timeout(Duration.ofSeconds(10))
.header("Content-Type", "application/json")
.header("x-api-key", apiKey)
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() < 200 || response.statusCode() >= 300) {
throw new RuntimeException("SMS send failed (HTTP " + response.statusCode() + "): " + response.body());
}
return response.body();
}
public static void main(String[] args) throws Exception {
String result = sendSms("+15551234567", "Hello from Java!");
System.out.println(result);
}
}Run with environment variables set:
export TEXTBEE_DEVICE_ID="your-device-id"
export TEXTBEE_API_KEY="your-api-key"
javac TextbeeSender.java && java TextbeeSenderNote on string formatting: The String.format approach above works for simple messages. For production, use a JSON library (Gson, Jackson, or org.json) to avoid escaping bugs with special characters in message bodies.
Option 1b: Native HttpClient with Jackson (recommended for production)
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.List;
import java.util.Map;
public class TextbeeSender {
private static final HttpClient CLIENT = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10)).build();
private static final ObjectMapper MAPPER = new ObjectMapper();
public static Map<?, ?> sendSms(String to, String message) throws Exception {
String apiKey = System.getenv("TEXTBEE_API_KEY");
String url = "https://api.textbee.dev/api/v1/gateway/send-sms";
String body = MAPPER.writeValueAsString(Map.of(
"recipients", List.of(to),
"message", message
));
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.timeout(Duration.ofSeconds(10))
.header("Content-Type", "application/json")
.header("x-api-key", apiKey)
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() < 200 || response.statusCode() >= 300) {
throw new RuntimeException("SMS send failed (HTTP " + response.statusCode() + "): " + response.body());
}
return MAPPER.readValue(response.body(), Map.class);
}
}Add Jackson to your pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.0</version>
</dependency>Or build.gradle:
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.0'Option 2: OkHttp (Java 8+)
OkHttp works on Java 8 and is popular in Android and backend Java projects:
import okhttp3.*;
import com.google.gson.Gson;
import java.util.List;
import java.util.Map;
public class TextbeeSender {
private static final OkHttpClient CLIENT = new OkHttpClient();
private static final Gson GSON = new Gson();
private static final MediaType JSON = MediaType.get("application/json");
public static String sendSms(String to, String message) throws Exception {
String apiKey = System.getenv("TEXTBEE_API_KEY");
String url = "https://api.textbee.dev/api/v1/gateway/send-sms";
String body = GSON.toJson(Map.of("recipients", List.of(to), "message", message));
Request request = new Request.Builder()
.url(url)
.addHeader("x-api-key", apiKey)
.post(RequestBody.create(body, JSON))
.build();
try (Response response = CLIENT.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new RuntimeException("SMS send failed (HTTP " + response.code() + "): " + response.body().string());
}
return response.body().string();
}
}
}Add OkHttp and Gson to pom.xml:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>Option 3: Spring Boot RestTemplate
In a Spring Boot application, RestTemplate integrates cleanly with your existing configuration:
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.*;
import org.springframework.beans.factory.annotation.Value;
import java.util.List;
import java.util.Map;
@Service
public class SmsService {
private final RestTemplate restTemplate;
@Value("${textbee.api-key}")
private String apiKey;
public SmsService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public Map<?, ?> sendSms(String to, String message) {
String url = "https://api.textbee.dev/api/v1/gateway/send-sms";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("x-api-key", apiKey);
Map<String, Object> body = Map.of(
"recipients", List.of(to),
"message", message
);
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(body, headers);
ResponseEntity<Map> response = restTemplate.exchange(
url, HttpMethod.POST, entity, Map.class
);
return response.getBody();
}
}Add to application.properties (reference environment variables):
textbee.device-id=${TEXTBEE_DEVICE_ID}
textbee.api-key=${TEXTBEE_API_KEY}Register a RestTemplate bean in your configuration:
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}What the API returns
On success:
{
"data": {
"success": true,
"message": "SMS added to queue for processing",
"smsBatchId": "abc123xyz",
"recipientCount": 1
}
}On failure, you get a non-2xx HTTP status. The response body contains an error message. All three examples above throw a RuntimeException with the status code and body: catch it in your calling code and handle accordingly (retry logic, alerting, fallback).
Sending to multiple recipients
Pass multiple numbers in the recipients list:
String body = MAPPER.writeValueAsString(Map.of(
"recipients", List.of("+15551111111", "+15552222222", "+15553333333"),
"message", "Reminder: team meeting at 3pm today."
));All recipients get the same message body in one API call and one batch ID.
Things worth knowing
Phone number format: Use E.164 (+15551234567). Local formats may work for same-country sends but E.164 is unambiguous and always correct.
Thread safety: HttpClient (Java 11+) and OkHttpClient are thread-safe and should be shared as singletons: create once, reuse everywhere. Don't instantiate a new client per request.
No per-message fee: Messages route through your own Android SIM. See pricing for the flat subscription tiers.
Opt-in compliance: Read the SMS compliance checklist before sending to lists.
Frequently asked questions
Is there a Java SDK for textbee?
Not yet. The REST API is simple enough: the examples above cover all common use cases. The API docs cover inbound webhooks, device status, and batch operations for anything beyond single sends.
What Java version is required?
Option 1 (native HttpClient) requires Java 11+. Options 2 (OkHttp) and 3 (Spring Boot) work on Java 8+. For new projects, Java 17 LTS or Java 21 LTS is recommended.
Can I use this in a Spring Boot application?
Yes. Option 3 above integrates directly into the Spring dependency injection model. For async sends (non-blocking), wrap the RestTemplate call in a @Async method or use WebClient from Spring WebFlux instead.
How do I handle async sending in Java?
Wrap the send call in a CompletableFuture:
CompletableFuture.runAsync(() -> {
try {
sendSms("+15551234567", "Your order has shipped!");
} catch (Exception e) {
log.error("SMS send failed", e);
}
});Or use Spring's @Async annotation on the service method for cleaner integration.
Keep going
- Full API reference: send, receive, webhooks, device management
- Receive SMS with webhooks: inbound SMS in a Java server
- Send SMS from Go, Python, PHP: same API, other languages
- Pricing: free tier available
Download textbee and send your first Java SMS in under 5 minutes.
Get more textbee in Google Search
Add textbee.dev as a preferred source. Our posts show up more often in your Google results.
You may also like

Send SMS from Go: No Twilio, Just Your Android Phone
Send real SMS from Go using textbee and your Android phone as the gateway. Native net/http, struct marshaling, error handling, and bulk send included.

Send Text Messages from PHP: SMS Gateway and API Tutorial with Your Android Phone
Send real text messages from PHP using textbee and your Android phone as the SMS gateway. Native cURL, Guzzle, and Laravel Http examples: zero per-message fees.

Send Text Messages from Node.js: SMS API Tutorial with Your Android Phone
Send real SMS messages from Node.js using your Android phone as the gateway. One async function, your own phone number, zero per-message fees.