Java 문자 발송 API 예제
JDK에 기본 포함된 HttpURLConnection 으로 센드엠 문자 발송 API를 호출하는 예제입니다. 별도 SDK가 필요 없습니다.
Java에서 문자를 어떻게 보내나요?
https://api.sendm.co.kr/v1/sms/send 에 POST 로 JSON을 보내고, 요청 헤더에 user-id 와 api-key 를 넣으면 됩니다. 응답 JSON의 code 가 "0" 이면 접수 성공입니다.
표준 HTTP 호출이라 HttpURLConnection, Apache HttpClient, OkHttp, Spring RestTemplate·WebClient 중 무엇을 써도 됩니다. 아래는 의존성이 가장 적은 HttpURLConnection 방식입니다.
웹 화면(JSP·JS)에서 직접 호출하지 마세요. 인증키가 소스에 노출되고, 호출 IP가 사용자마다 달라져 발송 IP 등록이 무의미해집니다. 반드시 서버 코드에서 호출하세요.
단문(SMS) 발송 전체 코드
SendmClient.java
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
public class SendmClient {
private static final String API_URL = "https://api.sendm.co.kr/v1/sms/send";
/* 소스에 직접 쓰지 말고 환경변수나 설정파일에서 읽으세요. */
private static final String USER_ID = System.getenv("SENDM_USER_ID");
private static final String API_KEY = System.getenv("SENDM_API_KEY");
public String sendSms(String callerNo, String receiveNos, String message) throws Exception {
JsonObject body = new JsonObject();
body.addProperty("callerNo", callerNo); // 등록·승인된 발신번호
body.addProperty("receiveNos", receiveNos); // 여러 건은 # 로 구분
body.addProperty("message", message);
// body.addProperty("smsType", "LMS"); // 장문이면 추가
// body.addProperty("title", "제목"); // 장문 제목
// body.addProperty("adYn", "Y"); // 광고문자면 Y
byte[] payload = new Gson().toJson(body).getBytes(StandardCharsets.UTF_8);
HttpURLConnection conn = (HttpURLConnection) new URL(API_URL).openConnection();
try {
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
conn.setRequestProperty("user-id", USER_ID);
conn.setRequestProperty("api-key", API_KEY);
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
os.write(payload);
}
int status = conn.getResponseCode();
/* 실패(4xx·5xx)일 때 getInputStream() 을 부르면 IOException 이 난다.
반드시 getErrorStream() 으로 읽어야 실패 사유를 볼 수 있다. */
InputStream in = (status == 200) ? conn.getInputStream() : conn.getErrorStream();
StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(
new InputStreamReader(in, StandardCharsets.UTF_8))) {
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
}
return sb.toString();
} finally {
conn.disconnect();
}
}
}
호출과 결과 판정
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
String raw = new SendmClient().sendSms(
"02-6959-8827", // 발신번호
"010-0000-0001#010-0000-0002", // 수신번호 (# 구분)
"주문이 접수되었습니다.");
JsonObject res = JsonParser.parseString(raw).getAsJsonObject();
if ("0".equals(res.get("code").getAsString())) {
long msgId = res.getAsJsonObject("data").get("msgId").getAsLong();
// msgId 를 저장해 두면 나중에 발송 결과를 조회할 수 있다
System.out.println("발송 접수 완료. msgId=" + msgId);
} else {
System.out.println("발송 실패 [" + res.get("code").getAsString() + "] "
+ res.get("message").getAsString());
}
code 는 숫자가 아니라 문자열 "0" 입니다. == 0 으로 비교하지 마세요.
발송 결과 조회와 잔여 건수
조회 API는 모두 GET 이고 인증 헤더만 같게 넣으면 됩니다.
GET 호출 공통 함수
public String get(String url) throws Exception {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
try {
conn.setRequestMethod("GET");
conn.setRequestProperty("user-id", USER_ID);
conn.setRequestProperty("api-key", API_KEY);
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
int status = conn.getResponseCode();
InputStream in = (status == 200) ? conn.getInputStream() : conn.getErrorStream();
StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(
new InputStreamReader(in, StandardCharsets.UTF_8))) {
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
}
return sb.toString();
} finally {
conn.disconnect();
}
}
// 잔여 코인·발송 가능 건수
get("https://api.sendm.co.kr/v2/info/coinInfo");
// 발송 상세 결과 (수신자별 resultCd 포함)
get("https://api.sendm.co.kr/v1/sms/sendList/" + msgId);
// 예약 발송 취소
get("https://api.sendm.co.kr/v1/sms/cancel/" + msgId);
발송 직후 바로 조회하면 대부분 대기 상태입니다. 결과는 통신사 리포트를 받아야 확정되며
waitCnt 가 최대 48시간 남을 수 있습니다. 발송 루프 안에서 즉시 조회하지 말고 배치나 스케줄러로 분리하세요.
운영에서 자주 막히는 지점
| 증상 | 원인 | 해결 |
|---|---|---|
| 한글이 깨져서 도착 | 요청 본문을 기본 인코딩으로 전송 | getBytes(StandardCharsets.UTF_8) 로 보내고 Content-Type 에 charset=UTF-8 명시 |
| 실패인데 예외만 남고 사유를 모름 | 4xx·5xx 응답에서 getInputStream() 호출 |
상태코드가 200이 아니면 getErrorStream() 으로 읽기 |
| 권한 없음으로 차단 | 호출 서버 IP가 미등록 | API 설정에서 발송 IP 등록. 서버 증설·이전 시 다시 등록 |
| 발신번호 오류 | callerNo 가 미등록·미승인 번호 |
발신번호 등록 후 사용 |
| 야간에만 실패 | 야간 발송 제한(21시~08시) | reserveYn=Y 와 sendDate 로 예약 전환 |
이어서 보면 좋은 문서
최종 업데이트 : 2026년 9월 16일 · 「센드엠 API 연동정의서 v3.0」 기준