데모에서 이메일 한 통을 보내는 것은 쉽습니다. 하지만 운영 환경에서 한 달에 10만 통을 보내려면 문제가 생기는 순간에 대비해야 합니다. 폐기된 키, 만료된 카드, 예상보다 빨리 끝나 버린 한 달, 상태가 좋지 않은 메일 서버 같은 순간 말입니다.
이 가이드에서는 Inbixio 발송 엔드포인트가 반환하는 모든 응답과 각 응답에 코드가 어떻게 대응해야 하는지, 그리고 서비스를 운영하면서 전달 상태를 지켜보는 방법을 설명합니다.
두 단계: 접수 후 전달
POST /api/send-email/ 호출은 두 단계로 처리됩니다.
- API 요청. Inbixio는 키와 키의 권한, 구독 상태, 월간 사용량, 요청 본문을 확인합니다. 모든 것이 정상이면
200을 반환하고 메시지를 대기열에 넣습니다. - 전달. 잠시 후 Inbixio가 여러분의 SMTP 서버에 연결해 메시지를 넘깁니다. 각 메시지는 sent(발송됨) 또는 failed(실패)로 기록되며, 이 결과가 대시보드의 수치에 반영됩니다.
따라서 200은 “받은편지함에 도착함”이 아니라 전달을 위해 접수됨을 뜻합니다. 1단계의 문제는 코드에서 처리할 수 있는 HTTP 오류로 돌아옵니다. 잘못된 SMTP 비밀번호 같은 2단계의 문제는 대시보드의 전달 실패율에 나타납니다. Inbixio는 메시지당 한 번만 전달을 시도하며, 실패한 전달을 재시도하지 않습니다.
모든 응답과 대응 방법
| 상태 | 본문 | 의미 | 코드에서 할 일 |
|---|---|---|---|
200 |
{"message": "Email queued successfully."} |
접수됨 | 완료 |
400 |
{"error": "to_email, subject, and message are required."} |
필드가 없거나 비어 있음 | 요청 수정, 재시도하지 않음 |
400 |
{"error": "to_email must be a single valid email address."} |
유효한 주소가 정확히 하나가 아님 | 요청 수정, 재시도하지 않음 |
400 |
{"error": "subject must be a single line of at most 500 characters."} |
제목이 너무 길거나 줄바꿈이 포함됨 | 요청 수정, 재시도하지 않음 |
400 |
{"error": "message must be text of at most 1,000,000 characters."} |
본문이 너무 큼 | 요청 수정, 재시도하지 않음 |
400 |
{"error": "No SMTP configuration found. Please add an email server first."} |
연결된 서버가 없음 | 대시보드에서 서버 추가 |
401 |
{"detail": "API key missing"} |
X-API-Key 헤더가 없음 |
설정 수정, 재시도하지 않음 |
401 |
{"detail": "Invalid API key"} |
잘못되었거나 갱신 또는 삭제된 키 | 키 교체, 팀에 알림 |
401 |
{"detail": "API key access not allowed"} |
키가 비활성화됨 | 다른 키 사용, 팀에 알림 |
402 |
{"error": "An active subscription is required to send emails."} |
구독이 비활성 상태 | 결제 문제 해결, 팀에 알림 |
403 |
{"error": "This API key does not have send permission."} |
키에 Send 권한이 없음 | Send 권한을 켜거나 다른 키 사용 |
429 |
{"error": "Monthly email limit reached for your plan.", "limit": 25000, "sent": 25000} |
요금제 한도 도달 | 업그레이드하거나 다음 달까지 발송 보류, 재시도하지 않음 |
429 |
{"detail": "Request was throttled. Expected available in 12 seconds."} |
짧은 시간에 이 키로 요청이 너무 많음(속도 제한) | Retry-After 헤더만큼 기다린 뒤 재시도 |
503 |
{"error": "Too many emails are waiting to be sent. Please retry in a few seconds."} |
일시적으로 바쁨 | Retry-After 헤더만큼 기다린 뒤 재시도 |
5xx / 타임아웃 |
— | 일시적인 문제 | 백오프를 적용해 재시도 |
대부분의 응답에서 오류 메시지는 error에 담기고, 인증 오류에서는 detail에 담기므로 두 필드를 모두 읽으세요.
const body = await res.json().catch(() => ({}));
const reason = body.error ?? body.detail ?? res.statusText;
나중에 성공할 수 있는 요청만 재시도하기
401을 백 번 재시도해도 키가 유효해지지는 않으며, 로그만 가득 찰 뿐입니다. 오류를 두 그룹으로 나누세요.
- 재시도할 오류: 네트워크 오류, 타임아웃,
5xx응답, 그리고 속도 제한429(detail메시지가 있는 쪽).Retry-After헤더가 알려 주는 시간만큼 기다리고, 헤더가 없으면 지터를 더한 지수 백오프를 사용하며, 몇 번 시도한 뒤에는 포기하세요. - 재시도하지 않을 오류:
400,401,402,403, 그리고 월간 한도429(limit과sent가 있는 쪽). 이 오류들은 사람이 개입하거나 요청을 바꿔야 합니다. 눈에 띄게 로그를 남기고, 특히401,402, 월간 한도429는 모든 이메일 발송을 멈추게 하므로 알림을 설정하세요.
// 5xx and the short-term rate limit can succeed later; the monthly limit (body has `limit`) can't.
const retryable = (status, body) => status >= 500 || (status === 429 && body.limit === undefined);
export async function sendWithRetry(payload, attempts = 4) {
for (let i = 0; i < attempts; i++) {
let res;
try {
res = await fetch('https://backend.inbixio.com/api/send-email/', {
method: 'POST',
headers: { 'X-API-Key': process.env.INBIXIO_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
signal: AbortSignal.timeout(15_000),
});
} catch (err) {
if (i === attempts - 1) throw err; // network error or timeout: retry
}
if (res?.ok) return res.json();
if (res) {
const body = await res.json().catch(() => ({}));
if (!retryable(res.status, body)) {
throw new Error(`Inbixio ${res.status}: ${body.error ?? body.detail ?? res.statusText}`);
}
}
const retryAfter = Number(res?.headers.get('Retry-After')) * 1000;
const delay = retryAfter || Math.min(30_000, 1000 * 2 ** i) * (0.5 + Math.random()); // 0.5s–30s with jitter
await new Promise((r) => setTimeout(r, delay));
}
throw new Error('Inbixio: gave up after retries');
}
중복 발송에 대해: 요청이 타임아웃되었더라도 실제로는 접수되었을 수 있습니다. 이때 재시도하면 같은 이메일이 두 번 발송될 수 있습니다. 영수증이나 알림이라면 대개 문제가 없지만, 중복 발송이 사용자를 혼란스럽게 할 수 있는 경우에는 보낸 내역을 자체 데이터베이스에 기록하고 재시도 전에 확인하세요.
월간 한도
각 요금제에는 월간 발송 가능한 이메일 수가 포함되어 있습니다. Starter는 25,000통, Growth는 150,000통입니다. Inbixio는 현재 달력 기준 월에 발송에 성공한 이메일 수를 셉니다. 한도에 도달하면 다음 달이 시작되거나 업그레이드할 때까지 발송 요청은 limit과 현재 sent 수를 담은 429를 반환합니다.
429가 올 때까지 기다리지 마세요.
- API Keys(API 키) 페이지의 Usage Limit(사용 한도) 카드에서 이번 달 발송 수를 요금제 한도와 비교해 볼 수 있습니다.
- 한도의 약 80%에 이르면 확인하도록 리마인더를 설정하고, 대규모 출시나 데이터 가져오기 전에는 업그레이드를 계획하세요.
- 단계별로 발송량을 추정하는 방법은 이메일 API 요금제 선택 가이드를 참고하세요.
전달 실패(2단계)
API가 메시지를 접수했지만 SMTP 서버가 이를 거부하면 전달 실패로 집계됩니다. 대시보드는 개별 메시지 목록 대신 최근 7일간의 Failed Deliveries(전달 실패) 비율을 보여 주므로, 비율을 지켜보다가 올라가면 서버 설정을 확인하세요. 흔한 원인은 다음과 같습니다.
- 인증 실패: 메일함 비밀번호가 바뀌었거나, 메일 제공업체가 이제 앱 비밀번호를 요구합니다.
- 연결 문제: 서버 설정의 호스트나 포트가 잘못되었습니다.
- 제공업체 한도: 메일 제공업체가 해당 메일함의 일일 발송량을 제한했습니다.
- 수신자 거부: 발송 중에 서버가 주소를 거부했습니다. 나중에 이메일로 도착하는 반송 메일은 Inbixio가 아니라 발신 메일함으로 가므로, 그 받은편지함도 확인하세요.
해결책은 거의 항상 Email Servers(이메일 서버) 설정이나 메일 제공업체 쪽에 있습니다. 흔한 사례는 SMTP 설정 완벽 정리에서 다룹니다.
운영 환경에서 모니터링할 항목
Inbixio 대시보드는 꼭 필요한 정보를 제공합니다.
- 최근 7일간의 Email Sent(발송 이메일) 수와 Failed Deliveries 비율, 그리고 각각의 직전 7일 대비 변화.
- Avg Latency(평균 지연 시간): SMTP 서버가 메일을 받아들이는 데 걸리는 시간. 갑자기 늘어나면 실패가 뒤따르는 경우가 많습니다.
- 연간 API 및 이메일 발송량 차트로 추세와 계절별 급증을 파악할 수 있습니다.
- 모든 API 호출의 Logs(로그): 이벤트 ID, 엔드포인트, 메서드, 상태 코드, 응답 시간, 타임스탬프.
여러분의 쪽에서는 200이 아닌 응답 수를 상태 코드별로 추적하고, 401, 402, 월간 한도 429가 나타나면 알림을 보내세요. 이는 모든 이메일 발송이 멈췄다는 뜻이며, 로그보다 사용자가 먼저 알아차리게 됩니다.
체크리스트
-
200은 “대기열에 추가됨”으로 취급하고, 전달 결과는 대시보드에서 확인하기 - 오류 응답에서
error와detail을 모두 읽기 - 네트워크 오류, 타임아웃,
5xx,503, 속도 제한429만Retry-After를 지켜 재시도하기 -
401,402, 월간 한도429에 알림 설정하기 - 출시와 데이터 가져오기 전에 Usage Limit 카드 확인하기
- Failed Deliveries 비율을 지켜보고 SMTP 설정을 신속하게 수정하기