mailnoo
v0.1.1
Published
Official Node.js SDK for Mailnoo — transactional email API
Maintainers
Readme
mailnoo
Mailnoo 공식 Node.js SDK. 의존성 0개 (Node 18+).
설치
npm install mailnoo발송
const { Mailnoo } = require('mailnoo');
const mailnoo = new Mailnoo({
apiKey: process.env.MAILNOO_API_KEY, // mn_live_... 또는 mn_test_...
});
const { results } = await mailnoo.emails.send({
from: '[email protected]', // 대시보드에 등록한 본인 도메인으로 교체
to: '[email protected]',
subject: '가입을 환영합니다',
html: '<p>안녕하세요!</p>',
});
// results: [{ id: '...', to: '[email protected]', status: 'queued' }]
// 상태 추적
const email = await mailnoo.emails.get(results[0].id);
// email.status: queued → sending → sent | delivery_unknown → delivered | bounced | complainedregistered-domain.com은 예시이며 그대로는 발송되지 않습니다. 테스트 키도 대시보드에 등록한
본인 발신 도메인의 주소를 사용해야 합니다.
cc / bcc · 예약 변경
// cc/bcc — 사용 시 to 는 1명 (하나의 메시지로 발송)
await mailnoo.emails.send({
from, to: '[email protected]', subject: '인보이스', html,
cc: '[email protected]',
bcc: ['[email protected]'],
});
// 예약 발송 → 시각 변경 → 취소
const { results } = await mailnoo.emails.send({ from, to, subject, html, send_at: '2026-08-01T09:00:00+09:00' });
await mailnoo.emails.update(results[0].id, { send_at: '2026-08-02T09:00:00+09:00' });
await mailnoo.emails.cancel(results[0].id);html과 text는 각각 UTF-8 512KB까지이며 JSON 요청 전체는 8MB까지입니다. 첨부는 최대
10개, base64 인코딩 전 원본 합계 약 5.5MB까지 지원합니다. 전체 JSON이 8MB를 넘으면
413 payload_too_large가 발생합니다.
배치 발송
const { results } = await mailnoo.emails.sendBatch([
{ from: '[email protected]', to: '[email protected]', subject: 'A', html: '<p>A</p>' },
{ from: '[email protected]', to: '[email protected]', subject: 'B', html: '<p>B</p>' },
]);
for (const result of results) {
console.log(result.index, result.status, result.code);
}공개 기본값은 메시지 25건·To/Cc/Bcc 전체 수신자 100명입니다. 유효한 배치는 모든 항목이
거절돼도 202와 results를 반환하므로 각 index, status, code를 확인하세요.
태그 · 메타데이터
발송에 붙인 값이 webhook payload 로 그대로 돌아옵니다 — 주문/유저 매칭에 쓰세요:
await mailnoo.emails.send({
from, to, subject, html,
tags: ['order-confirm'], // 최대 5개, 로그 필터에도 사용
metadata: { order_id: '8231', user_id: 'u1' }, // 최대 10키
});
// webhook: { type: 'delivered', data: { ..., tags: ['order-confirm'], metadata: { order_id: '8231', ... } } }통합 이메일 로그 조회
기본 조회에는 outbound 발송과 inbound 수신 로그가 모두 포함됩니다.
const { items, total } = await mailnoo.emails.list({
status: 'bounced', // 상태 필터
to: '@gmail.com', // 수신자 부분 일치
tag: 'order-confirm', // 태그 필터
direction: 'outbound', // 생략하면 outbound + inbound
limit: 50,
});템플릿 발송
대시보드에서 만든 템플릿의 이름(또는 ID)으로 발송할 수 있습니다.
본문은 서버에 저장되어 있으니 variables 만 넘기면 됩니다:
await mailnoo.emails.send({
from: '[email protected]',
to: '[email protected]',
template_id: 'welcome-email', // 대시보드 → 템플릿
variables: { name: '정환', code: '482910' }, // {{name}}, {{code}} 치환
});변수가 누락되면 422 template_missing_variables 로 거절됩니다 (조용한 빈값 치환 없음).
중복 발송 방지 (Idempotency)
네트워크 타임아웃 후 재시도해도 메일이 두 번 나가지 않습니다:
await mailnoo.emails.send(payload, { idempotencyKey: `welcome-${userId}` });테스트 모드
mn_test_ 키를 쓰면 실제 발송 없이 전체 파이프라인이 시뮬레이션됩니다.
수신자 주소로 시나리오를 지정할 수 있습니다:
await mailnoo.emails.send({ from, to: '[email protected]', ... }); // → delivered
await mailnoo.emails.send({ from, to: '[email protected]', ... }); // → bounced 이벤트 발생
await mailnoo.emails.send({ from, to: '[email protected]', ... }); // → complained 이벤트 발생Webhook 서명 검증
const express = require('express');
const { Mailnoo } = require('mailnoo');
const app = express();
app.post('/webhooks/mailnoo', express.text({ type: 'application/json' }), (req, res) => {
const ok = Mailnoo.verifyWebhookSignature({
payload: req.body, // 반드시 raw string (express.json() 쓰면 안 됨)
signature: req.headers['x-mailnoo-signature'],
timestamp: req.headers['x-mailnoo-timestamp'],
secret: process.env.MAILNOO_WEBHOOK_SECRET, // whsec_...
});
if (!ok) return res.status(403).end();
const event = JSON.parse(req.body); // { type: 'bounced', created_at, data: {...} }
// ... 처리
res.status(200).end();
});에러 처리
const { MailnooError } = require('mailnoo');
try {
await mailnoo.emails.send(payload);
} catch (e) {
if (e instanceof MailnooError) {
console.error(e.code); // 'domain_not_verified', 'rate_limited', ...
console.error(e.message); // 사람이 읽을 수 있는 원인 + 해결 힌트
console.error(e.docsUrl); // 해당 에러 문서 링크
}
}단건 발송에서 모든 수신자가 일/월 쿼터에 막히면 MailnooError.status는 429, code는
daily_quota_exceeded 또는 monthly_quota_exceeded입니다. 배치는 항목별 결과를 보존하기
위해 유효한 요청을 202로 반환합니다.
