Relay API 설계: Cloudflare Workers로 메일 전송 기반을 구축

이 페이지는 일본어 원문을 기계 번역한 것입니다. 일본어 원문 보기

1. 왜 외부 메일 제공업체인 API를 사용하지 않았는가

메모를 이메일로 전송하는 앱을 만들 때 가장 먼저 떠오르는 것은 대형 메일 제공업체의 전송 API입니다. 하지만 개인 개발자에게는 Google OAuth 심사의 장벽이 매우 높았습니다.

Google OAuth 심사를 통과하지 않은 앱에는 “이 앱은 Google에서 확인되지 않았습니다”라는 경고 화면이 표시됩니다. 메모 앱에게 이 경고는 치명적입니다. 사용자는 자신의 생각과 개인 정보를 메모로 전송합니다. 그 첫 번째 경험에서 “검증되지 않았습니다”라는 메시지가 표시되면, 누가 이 앱을 신뢰할까요?

Google OAuth 심사 신청 절차는 개인 개발자에게 험난한 길입니다. 개인정보 보호정책 준비, 범위의 정당성 설명, 보안 평가—대기업 팀이라면 그렇지만, 혼자 개발하는 앱에게는 메일 전송이라는 단일 기능을 위해 지불하는 비용이 너무 큽니다.

필요했던 것은 OAuth 심사의 복잡함 없이, 사용자의 신뢰를 손상시키지 않고 이메일을 전송할 수 있는 솔루션이었습니다. 그 답은 자체 Relay API입니다.

2. Cloudflare Workers + Resend API 아키텍처

Relay API의 아키텍처는 단순하면서도 견고합니다. iOS 앱으로부터 요청을 받아 메일 전송 서비스에 중계합니다—그것만을 위해 특화된 설계입니다.

iOS 앱 → 릴레이 API (Cloudflare 작업자) → Resend API → 이메일 전달

Cloudflare Workers는 전 세계의 엣지 위치에서 TypeScript 코드를 실행하는 서버리스 플랫폼입니다. Cloudflare의 설명에 따르면, isolate라는 가벼운 실행 환경에서 코드를 실행하기 때문에 가상 머신형 서버리스에서 발생하는 콜드 스타트가 없습니다.

Resend API는 현대적인 이메일 전송 서비스입니다. SPF/DKIM/DMARC를 설정하기 쉽고, TypeScript에서 쉽게 호출할 수 있습니다.

비용 측면에서는 Cloudflare Workers의 무료 플랜은 1일 100000 요청까지이며, Resend의 무료 플랜은 1일 100통·월 3,000통까지 사용할 수 있습니다(2026년 10월 기준 각사의 요금 페이지). 작게 시작하여 전송량에 맞춰 유료 플랜으로 전환할 수 있는 구성입니다.

3. 이메일 주소 검증(6자리 코드 방식)

Relay API는 검증된 이메일 주소로만 메모를 전송합니다. 이는 악용 방지를 위한 가장 기본적인 방어층입니다.

메모 전송을 시작하기 전에, 전송 대상 이메일 주소를 검증하는 흐름이 필요합니다.

  • 사용자가 앱에 이메일 주소를 입력합니다
  • Relay API가 6자리 검증 코드를 해당 주소로 전송
  • 사용자가 수신한 6 자리 코드를 앱에 입력
  • 검증이 완료되었습니다. 이후, 해당 이메일 주소로 메모 전송이 허용됩니다

이 메커니즘을 통해 타인의 이메일 주소로 무단으로 메모가 전송되는 것을 방지합니다. 검증 코드는 해당 주소의 수신함에 도착하므로, 수신함을 확인할 수 없는 사람은 해당 주소를 수신지로 확인할 수 없습니다.

검증은 이메일 주소당 한 번만 가능합니다. 검증이 한 번 완료되면, 이후에는 코드 입력 없이 메모를 계속 전송할 수 있습니다.

4. 다층 레이트 제한 구현

메일 전송 API의 악용을 방지하기 위해 여러 레이어에서 속도 제한을 구현하고 있습니다.

const RATE_LIMITS = {
  devicePerMinute: 30,
  devicePerDay: 200,
  ipPerHour: 120,
  globalPerDay: 300,
};
장치 레벨
디바이스 단위 제한
1대의 디바이스에서 과도한 전송을 방지합니다. 1분당 30건, 1분당 200건의 상한을 설정합니다. 일반적인 메모 사용으로는 도달할 수 없는 임계값이지만, 자동화에 의한 대량 전송을 중단합니다.
IP 레벨
IP 주소 단위 제한
동일 네트워크에서의 대량 요청을 제한합니다. 1시간당 120건. 다중 디바이스를 이용한 공격으로부터도 인프라를 보호합니다.
글로벌
글로벌 제한
인프라 전체의 보호. 1당 300건의 글로벌 상한을 최종 고정으로 두고 있습니다(각 상한의 수치는 설계 시점의 것이며 변경될 수 있습니다).
2026-09 추가
현재 상한
단말별 상한과 전체 1일 상한은 2026년 6월에 제거되었습니다. 현재 전송 상한은 IP 주소당 1 시간당 상한입니다.

카운터는 Cloudflare KV에 저장되며, 각 시간 창마다 리셋됩니다. 일반적인 전송은 통과하면서, 불법적인 대량 접근을 억제합니다.

5. 멱등성: 동일한 메모를 이중으로 전송하지 않기 위한 설계

네트워크 통신에는 불확실성이 따릅니다. 전송 버튼을 누른 후 응답이 돌아올 때까지 통신이 끊기는 경우가 있습니다. 앱은 타임아웃으로 판단하여 재전송을 시도하지만, 실제로 최초 요청은 서버에 도착해 있었습니다——흔한 시나리오입니다.

이 경우에는 멱등성(idempotency)으로 준비합니다.

  • 각 메모에 고유한 UUID(메시지 ID)를 부여합니다
  • Relay API는 해당 메시지 ID를 메일 전송 서비스(Resend)에 대한 요청의 멱등키(Idempotency-Key)로 전달합니다
  • Resend은 동일한 키를 24시간 동안 기억하고 있으며, 동일한 내용의 요청이 다시 오면 이메일을 보내지 않고 이전과 동일한 응답을 반환합니다
  • 앱에는 성공 응답이 반환됩니다(2회차도 1회차와 동일한 응답)

이 설계에 따라 네트워크가 불안정하고 재시도가 발생하더라도 24 시간 동안 동일한 메모가 중복 전송되지 않습니다(Resend이 키를 기억하고 있는 기간). 그 이후의 재송송은 구분할 수 없으므로, 중복을 중단할 수 있는 것은 이 기간 내에 있습니다.

6. 에지 컴퓨팅의 장점

Cloudflare Workers를 메일 전송 기반으로 채택한 가장 큰 이유는 엣지 컴퓨팅의 본질적인 장점에 있습니다.

지연
전 세계의 엣지 위치 = 낮은 지연 시간
Cloudflare은 전 세계 300 이상의 도시에 거점을 두고 있습니다. 요청은 이용자와 가까운 지점에서 처리되므로, 먼 1 서버까지 왕복하는 것보다 통신 거리가 짧아집니다(응답까지의 시간은 이메일 전송 서비스 처리를 포함하여 달라집니다).
콜드 스타트
가상 머신형 콜드 스타트가 없습니다
가상 머신이나 컨테이너에서 동작하는 서버리스에서는, 한동안 사용되지 않은 후의 첫 번째 요청에서 부팅을 기다리는 경우(콜드 스타트)가 있습니다. Cloudflare Workers는 격리된 상태에서 동작하기 때문에 이 대기가 발생하지 않는다고 Cloudflare은 설명하고 있습니다.
운영
인프라 관리가 필요 없는 자동 스케일링
서버 관리, 용량 계획, 스케일링 설정—이 모든 것이 필요하지 않습니다. 요청이 증가하면 자동으로 확장되고, 유휴 시에는 비용이 발생하지 않습니다.

메모 앱에게 이 조합은 다루기 쉬운 선택이었습니다. 이용자에 가까운 거점에서 처리가 시작되고, 서버 관리가 필요 없으며, 작은 규모라면 비용도 절감할 수 있습니다. 그것이 엣지 컴퓨팅에서 릴레이 API를 만든 이유입니다.

이 기술 기반 위에 구축된 “SimpleMemo”을 꼭 사용해 보시기 바랍니다.

App Store에서 다운로드

참고문헌