본문으로 건너뛰기
runlot
데이터이메일

이메일

워커에서 메일을 보내고, 프로젝트 주소로 온 메일을 워커가 수신하게 하세요. runlot이 발신 평판을 관리하고 수신 메일 서버를 운영합니다.

모든 프로젝트에는 메일 주소가 하나씩 있습니다. org acme의 shop 프로젝트라면:

주소
발신[email protected]
수신*@shop.acme.runlot.email — 로컬 파트는 무엇이든 가능합니다

주소는 대시보드의 Email 탭이나 runlot email에서 확인할 수 있습니다.

발신

export default {
  async fetch(request, env) {
    await env.email.send({
      to: "[email protected]",           // string or array (up to 10)
      subject: "Order received",
      text: "Thanks. Shipping soon.",
      html: "<p>Thanks. Shipping soon.</p>",   // text or html is required
      replyTo: "[email protected]",       // optional
    });
    return new Response("ok");
  },
};

기본값에는 from이 없습니다 — 발신자는 프로젝트 주소입니다. 직접 보유한 도메인으로 보내려면 다음 절을 보세요. 호출은 { id }를 반환하고 실패 시 예외를 던집니다 — e.status는 HTTP 상태 코드입니다 (429는 시간별 한도를 의미합니다).

직접 보유한 도메인으로 보내기

도메인을 추가하고 레코드 세 개를 공개하면 from이 동작합니다.

runlot email domain add acme.com

공개할 레코드가 출력됩니다. 이 중 세 개는 필수이며, 없으면 확인이 끝나지 않습니다.

종류이름값
CNAME<token1>._domainkey.acme.com<token1>.dkim.amazonses.com
CNAME<token2>._domainkey.acme.com<token2>.dkim.amazonses.com
CNAME<token3>._domainkey.acme.com<token3>.dkim.amazonses.com

나머지 두 개는 권장 사항이고, 확인이 이것을 기다리지 않습니다.

종류이름값
TXTacme.comv=spf1 include:amazonses.com ~all
TXT_dmarc.acme.comv=DMARC1; p=none; adkim=r; aspf=r

SPF 레코드를 소프트 페일(~all)로 두는 데에는 이유가 있습니다. 보유한 도메인은 이미 다른 곳에서도 메일을 보내고 있을 가능성이 큰데, 저희가 하드 페일을 얹으면 그 메일이 끊깁니다. 더 조이는 것은 직접 하시면 됩니다.

runlot email domain verify acme.com

확인 중인 도메인은 저희도 1분마다 다시 확인합니다. 레코드를 공개해 두고 다른 일을 하셔도 됩니다. DNS가 퍼지는 데에는 몇 분에서 몇 시간이 걸리고, 72시간 동안 레코드가 보이지 않으면 실패로 표시되며 다시 추가하시면 됩니다.

해당 도메인의 존을 저희가 호스팅한다면(runlot dns) --publish를 붙여 주세요. 레코드를 대신 적어 드립니다. 직접 적으신 레코드는 덮어쓰지 않습니다.

verified로 바뀌면 이렇게 쓸 수 있습니다.

await env.email.send({
  from: "[email protected]",             // 확인된 도메인의 로컬 파트는 자유입니다
  to: "[email protected]",
  subject: "Order received",
  text: "Thanks. Shipping soon.",
});

확인된 도메인의 서브도메인도 됩니다 — [email protected]은 acme.com이 덮습니다. 그 밖의 도메인을 from에 쓰면 from_not_verified로 거절되고, 아직 확인 중인 도메인도 마찬가지입니다.

runlot email domain list              # 도메인과 상태
runlot email domain rm acme.com       # 삭제 (admin)

수신은 여전히 *@<project>.<org>.runlot.email입니다. 보유한 도메인의 MX를 저희 쪽으로 돌리는 것은 아직 지원하지 않습니다.

수신

export default {
  async fetch(request, env) { /* … */ },

  async email(message, env, ctx) {
    // message.from, message.to, message.headers (Headers), message.raw (ReadableStream), message.rawSize
    const raw = await new Response(message.raw).text();
    await env.db.query("insert into inbox (from_addr, to_addr, raw) values ($1, $2, $3)",
      [message.from, message.to, raw]);

    // To refuse — the sender sees this text
    if (message.headers.get("authentication-results")?.includes("spf=fail")) {
      message.setReject("SPF check failed");
    }
  },
};

email 핸들러는 수신한 메시지마다 한 번씩 호출됩니다. message.raw는 헤더를 포함한 전체 메시지입니다 — 첨부 파일에는 postal-mime 같은 파서를 사용하세요.

핸들러를 내보내지 않는 프로젝트로 보낸 메일은 반송됩니다. 핸들러가 예외를 던지면 발신자가 나중에 재시도합니다 (일시적 실패로 처리됩니다).

제한 사항

값
시간당 발신 수Free 30 · Pro 300 — 로그인 메일(env.auth)과 공유됩니다
메시지당 수신자 수10
시간당 수신 수600
수신 메시지 크기25 MiB
핸들러 실행 시간30초

발신 한도를 초과하면 429를 받고, 수신 한도를 초과하면 발신자에게 나중에 다시 시도하라는 응답이 전달됩니다.

발신·수신 내역 확인

발신·수신된 모든 메시지는 대시보드의 Email 탭에서 한 줄로 표시됩니다: 시간, 방향, from, to, 제목, 결과, 크기. 줄을 클릭하면 헤더와 본문을 볼 수 있고, 원본 메시지는 .eml로 다운로드됩니다. HTML 본문은 렌더링되지 않고 소스로 표시됩니다.

요금제보존 기간
무료30일
프로365일
runlot email log                       # latest 50
runlot email log --direction in        # received only
runlot email log --cursor <cursor>     # next page
runlot email raw <mailId> > mail.eml   # raw message

수신 메일의 결과는 핸들러가 한 작업입니다 — 처리됨, 거부됨, 핸들러 없음, 핸들러 오류. 발신 메일의 결과는 릴레이가 수락했는지 여부이며, 수락하지 않았다면 그 이유입니다.

여기 없는 것

  • 보유한 도메인으로 수신. 발신은 위에서 됩니다. 보유한 도메인의 MX는 아직 지원하지 않습니다.
  • 발신 시 첨부 파일. text와 html만 지원합니다.
  • 뉴스레터. 메시지당 수신자 10명이 절대 상한입니다.
  • forward() / reply(). 둘 다 env.email.send로 처리할 수 있습니다.

CLI

runlot email            # address and sent/received counts for the last hour and 24 hours
runlot email --json
runlot email delete     # turn off (admin). Mail to this address will bounce

runlot email domain add acme.com [--publish]   # send from your own domain
runlot email domain list                       # domains and their state
runlot email domain verify acme.com            # re-check now
runlot email domain rm acme.com                # remove (admin)

이 페이지의 목차