mailumi 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/cjs/index.d.ts +102 -2
- package/dist/cjs/index.js +1 -5
- package/dist/index.d.ts +102 -2
- package/dist/index.js +1 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -132,12 +132,18 @@ export async function POST(request: Request) {
|
|
|
132
132
|
if (error) return new Response(error.message, { status: 401 });
|
|
133
133
|
|
|
134
134
|
if (event.type === 'email.received') {
|
|
135
|
-
|
|
135
|
+
const { from, reply_to, subject, text, html, message_id, spam, attachments } = event.data;
|
|
136
|
+
// spam is a boolean; attachments have filename, content_type, size and download_url
|
|
137
|
+
}
|
|
138
|
+
if (event.type === 'email.bounced') {
|
|
139
|
+
const { recipient, bounce } = event.data; // bounce.type is "Permanent" or "Transient"
|
|
136
140
|
}
|
|
137
141
|
return new Response('OK');
|
|
138
142
|
}
|
|
139
143
|
```
|
|
140
144
|
|
|
145
|
+
`event.data` is typed by `event.type`: `EmailReceivedData` for `email.received`, and `EmailEventData` for events about email you sent, which is the email plus `recipient` and a detail such as `delivery`, `bounce` or `click`. Every field is described under [Receiving email](https://mailumi.com/docs#receiving) and [Webhooks](https://mailumi.com/docs#webhooks).
|
|
146
|
+
|
|
141
147
|
`headers` can be a `Headers` object, Node's `req.headers`, or `{ id, timestamp, signature }`. Deliveries can repeat, so store `event.id` and skip ids you have seen. Events: `email.sent`, `email.delivered`, `email.delivery_delayed`, `email.bounced`, `email.complained`, `email.opened`, `email.clicked`, `email.failed`, `email.unsubscribed` and `email.received`.
|
|
142
148
|
|
|
143
149
|
## Audiences and contacts
|
|
@@ -215,7 +221,7 @@ Mailumi publishes [llms.txt](https://mailumi.com/llms.txt), [llms-full.txt](http
|
|
|
215
221
|
## Links
|
|
216
222
|
|
|
217
223
|
- [Documentation](https://mailumi.com/docs)
|
|
218
|
-
- [Pricing](https://mailumi.com/pricing): the free plan includes
|
|
224
|
+
- [Pricing](https://mailumi.com/pricing): the free plan includes 1,500 emails a month
|
|
219
225
|
- [Support](https://mailumi.com/contact)
|
|
220
226
|
|
|
221
227
|
## Versioning
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The official Mailumi SDK. Works anywhere `fetch` exists: Node.js 18+, Bun, Deno and Cloudflare Workers.
|
|
3
3
|
* Every method resolves to `{ data, error }` and never throws for API errors.
|
|
4
4
|
*/
|
|
5
|
-
export declare const VERSION = "1.
|
|
5
|
+
export declare const VERSION = "1.1.0";
|
|
6
6
|
export type ErrorCode = 'invalid_request' | 'unauthorized' | 'plan_limit_reached' | 'forbidden' | 'not_found' | 'method_not_allowed' | 'conflict' | 'payload_too_large' | 'rate_limited' | 'internal_error' | 'service_unavailable' | 'network_error' | 'missing_api_key' | 'invalid_signature' | 'missing_webhook_secret';
|
|
7
7
|
export interface MailumiError {
|
|
8
8
|
name: 'MailumiError';
|
|
@@ -189,6 +189,105 @@ export interface WebhookEvent<T = Record<string, any>> {
|
|
|
189
189
|
created_at: string;
|
|
190
190
|
data: T;
|
|
191
191
|
}
|
|
192
|
+
interface EmailFields {
|
|
193
|
+
email_id: string;
|
|
194
|
+
domain_id: string;
|
|
195
|
+
from: string;
|
|
196
|
+
to: string[];
|
|
197
|
+
subject: string;
|
|
198
|
+
last_event: string;
|
|
199
|
+
tags: Record<string, string>;
|
|
200
|
+
created_at: string;
|
|
201
|
+
}
|
|
202
|
+
export interface ReceivedAttachment {
|
|
203
|
+
id: string;
|
|
204
|
+
filename: string;
|
|
205
|
+
content_type: string;
|
|
206
|
+
/** Set for inline images that the HTML shows with `cid:`. */
|
|
207
|
+
content_id: string | null;
|
|
208
|
+
/** Size in bytes. */
|
|
209
|
+
size: number;
|
|
210
|
+
/** Download it server-side with `mailumi.emails.attachment({ id: email_id, index })` or a key with email:read. */
|
|
211
|
+
download_url: string;
|
|
212
|
+
}
|
|
213
|
+
/** `data` of an `email.received` event. */
|
|
214
|
+
export interface EmailReceivedData extends EmailFields {
|
|
215
|
+
direction: 'inbound';
|
|
216
|
+
status: 'received';
|
|
217
|
+
scheduled_at: null;
|
|
218
|
+
error: null;
|
|
219
|
+
/** `Name <address>`, or only the address when the email has no name. */
|
|
220
|
+
from: string;
|
|
221
|
+
/** The recipients at this domain, in lowercase. */
|
|
222
|
+
to: string[];
|
|
223
|
+
cc: string[];
|
|
224
|
+
reply_to: string[];
|
|
225
|
+
/** The Message-ID header with its angle brackets, for In-Reply-To and References when you reply. */
|
|
226
|
+
message_id: string | null;
|
|
227
|
+
/** Empty when the email has no plain-text part. */
|
|
228
|
+
text: string;
|
|
229
|
+
/** Empty when the email has no HTML part. It is the sender's HTML: sanitize it before showing it. */
|
|
230
|
+
html: string;
|
|
231
|
+
/** `true` when the Amazon SES spam check flagged the email. */
|
|
232
|
+
spam: boolean;
|
|
233
|
+
attachments: ReceivedAttachment[];
|
|
234
|
+
}
|
|
235
|
+
/** `data` of an event about an email you sent: the email as it is now, plus the detail for that event. */
|
|
236
|
+
export interface EmailEventData extends EmailFields {
|
|
237
|
+
direction: 'outbound';
|
|
238
|
+
status: string;
|
|
239
|
+
scheduled_at: string | null;
|
|
240
|
+
error: string | null;
|
|
241
|
+
/** The recipient the event is about. Not set on email.sent and email.failed, nor on opens and clicks of an email with more than one recipient. */
|
|
242
|
+
recipient?: string;
|
|
243
|
+
delivery?: {
|
|
244
|
+
smtp_response: string | null;
|
|
245
|
+
};
|
|
246
|
+
delay?: {
|
|
247
|
+
type: string | null;
|
|
248
|
+
expires_at: string | null;
|
|
249
|
+
message: string | null;
|
|
250
|
+
};
|
|
251
|
+
bounce?: {
|
|
252
|
+
type: 'Permanent' | 'Transient' | (string & {}) | null;
|
|
253
|
+
sub_type: string | null;
|
|
254
|
+
message: string | null;
|
|
255
|
+
};
|
|
256
|
+
complaint?: {
|
|
257
|
+
type: string | null;
|
|
258
|
+
};
|
|
259
|
+
open?: {
|
|
260
|
+
ip_address: string | null;
|
|
261
|
+
user_agent: string | null;
|
|
262
|
+
};
|
|
263
|
+
click?: {
|
|
264
|
+
link: string | null;
|
|
265
|
+
ip_address: string | null;
|
|
266
|
+
user_agent: string | null;
|
|
267
|
+
};
|
|
268
|
+
failed?: {
|
|
269
|
+
reason: string;
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
/** The event `verifyWebhook` returns. Check `event.type` and `event.data` has the matching fields. */
|
|
273
|
+
export type MailumiWebhookEvent = {
|
|
274
|
+
id: string;
|
|
275
|
+
type: 'email.received';
|
|
276
|
+
created_at: string;
|
|
277
|
+
data: EmailReceivedData;
|
|
278
|
+
} | {
|
|
279
|
+
id: string;
|
|
280
|
+
type: Exclude<WebhookEventType, 'email.received' | 'webhook.test'>;
|
|
281
|
+
created_at: string;
|
|
282
|
+
data: EmailEventData;
|
|
283
|
+
} | {
|
|
284
|
+
id: string;
|
|
285
|
+
type: 'webhook.test';
|
|
286
|
+
created_at: string;
|
|
287
|
+
data: {
|
|
288
|
+
message: string;
|
|
289
|
+
};
|
|
290
|
+
};
|
|
192
291
|
export interface VerifyWebhookOptions {
|
|
193
292
|
/** The raw request body exactly as received, before any JSON parsing. */
|
|
194
293
|
payload: string | Uint8Array;
|
|
@@ -203,7 +302,8 @@ export interface VerifyWebhookOptions {
|
|
|
203
302
|
* Checks the Standard Webhooks signature of a Mailumi webhook and returns the parsed event.
|
|
204
303
|
* Store `event.id` and skip ids you have seen: a delivery can arrive more than once.
|
|
205
304
|
*/
|
|
206
|
-
export declare function verifyWebhook
|
|
305
|
+
export declare function verifyWebhook(options: VerifyWebhookOptions): Promise<Result<MailumiWebhookEvent>>;
|
|
306
|
+
export declare function verifyWebhook<T>(options: VerifyWebhookOptions): Promise<Result<WebhookEvent<T>>>;
|
|
207
307
|
/** Converts the SDK's camelCase options to the API's request body. snake_case keys are accepted too. */
|
|
208
308
|
export declare function toApiEmail(o: SendEmailOptions & Record<string, any>): Record<string, unknown>;
|
|
209
309
|
export declare class Mailumi {
|
package/dist/cjs/index.js
CHANGED
|
@@ -7,7 +7,7 @@ exports.toApiEmail = toApiEmail;
|
|
|
7
7
|
* The official Mailumi SDK. Works anywhere `fetch` exists: Node.js 18+, Bun, Deno and Cloudflare Workers.
|
|
8
8
|
* Every method resolves to `{ data, error }` and never throws for API errors.
|
|
9
9
|
*/
|
|
10
|
-
exports.VERSION = '1.
|
|
10
|
+
exports.VERSION = '1.1.0';
|
|
11
11
|
const DEFAULT_BASE_URL = 'https://mailumi.com/api/v1';
|
|
12
12
|
function header(h, name, short) {
|
|
13
13
|
if (typeof h.get === 'function')
|
|
@@ -29,10 +29,6 @@ function sameText(a, b) {
|
|
|
29
29
|
diff |= (a.charCodeAt(i) || 0) ^ (b.charCodeAt(i) || 0);
|
|
30
30
|
return diff === 0;
|
|
31
31
|
}
|
|
32
|
-
/**
|
|
33
|
-
* Checks the Standard Webhooks signature of a Mailumi webhook and returns the parsed event.
|
|
34
|
-
* Store `event.id` and skip ids you have seen: a delivery can arrive more than once.
|
|
35
|
-
*/
|
|
36
32
|
async function verifyWebhook({ payload, headers, secret, tolerance = 300 }) {
|
|
37
33
|
const key = secret ?? globalThis.process?.env?.MAILUMI_WEBHOOK_SECRET;
|
|
38
34
|
if (!key)
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The official Mailumi SDK. Works anywhere `fetch` exists: Node.js 18+, Bun, Deno and Cloudflare Workers.
|
|
3
3
|
* Every method resolves to `{ data, error }` and never throws for API errors.
|
|
4
4
|
*/
|
|
5
|
-
export declare const VERSION = "1.
|
|
5
|
+
export declare const VERSION = "1.1.0";
|
|
6
6
|
export type ErrorCode = 'invalid_request' | 'unauthorized' | 'plan_limit_reached' | 'forbidden' | 'not_found' | 'method_not_allowed' | 'conflict' | 'payload_too_large' | 'rate_limited' | 'internal_error' | 'service_unavailable' | 'network_error' | 'missing_api_key' | 'invalid_signature' | 'missing_webhook_secret';
|
|
7
7
|
export interface MailumiError {
|
|
8
8
|
name: 'MailumiError';
|
|
@@ -189,6 +189,105 @@ export interface WebhookEvent<T = Record<string, any>> {
|
|
|
189
189
|
created_at: string;
|
|
190
190
|
data: T;
|
|
191
191
|
}
|
|
192
|
+
interface EmailFields {
|
|
193
|
+
email_id: string;
|
|
194
|
+
domain_id: string;
|
|
195
|
+
from: string;
|
|
196
|
+
to: string[];
|
|
197
|
+
subject: string;
|
|
198
|
+
last_event: string;
|
|
199
|
+
tags: Record<string, string>;
|
|
200
|
+
created_at: string;
|
|
201
|
+
}
|
|
202
|
+
export interface ReceivedAttachment {
|
|
203
|
+
id: string;
|
|
204
|
+
filename: string;
|
|
205
|
+
content_type: string;
|
|
206
|
+
/** Set for inline images that the HTML shows with `cid:`. */
|
|
207
|
+
content_id: string | null;
|
|
208
|
+
/** Size in bytes. */
|
|
209
|
+
size: number;
|
|
210
|
+
/** Download it server-side with `mailumi.emails.attachment({ id: email_id, index })` or a key with email:read. */
|
|
211
|
+
download_url: string;
|
|
212
|
+
}
|
|
213
|
+
/** `data` of an `email.received` event. */
|
|
214
|
+
export interface EmailReceivedData extends EmailFields {
|
|
215
|
+
direction: 'inbound';
|
|
216
|
+
status: 'received';
|
|
217
|
+
scheduled_at: null;
|
|
218
|
+
error: null;
|
|
219
|
+
/** `Name <address>`, or only the address when the email has no name. */
|
|
220
|
+
from: string;
|
|
221
|
+
/** The recipients at this domain, in lowercase. */
|
|
222
|
+
to: string[];
|
|
223
|
+
cc: string[];
|
|
224
|
+
reply_to: string[];
|
|
225
|
+
/** The Message-ID header with its angle brackets, for In-Reply-To and References when you reply. */
|
|
226
|
+
message_id: string | null;
|
|
227
|
+
/** Empty when the email has no plain-text part. */
|
|
228
|
+
text: string;
|
|
229
|
+
/** Empty when the email has no HTML part. It is the sender's HTML: sanitize it before showing it. */
|
|
230
|
+
html: string;
|
|
231
|
+
/** `true` when the Amazon SES spam check flagged the email. */
|
|
232
|
+
spam: boolean;
|
|
233
|
+
attachments: ReceivedAttachment[];
|
|
234
|
+
}
|
|
235
|
+
/** `data` of an event about an email you sent: the email as it is now, plus the detail for that event. */
|
|
236
|
+
export interface EmailEventData extends EmailFields {
|
|
237
|
+
direction: 'outbound';
|
|
238
|
+
status: string;
|
|
239
|
+
scheduled_at: string | null;
|
|
240
|
+
error: string | null;
|
|
241
|
+
/** The recipient the event is about. Not set on email.sent and email.failed, nor on opens and clicks of an email with more than one recipient. */
|
|
242
|
+
recipient?: string;
|
|
243
|
+
delivery?: {
|
|
244
|
+
smtp_response: string | null;
|
|
245
|
+
};
|
|
246
|
+
delay?: {
|
|
247
|
+
type: string | null;
|
|
248
|
+
expires_at: string | null;
|
|
249
|
+
message: string | null;
|
|
250
|
+
};
|
|
251
|
+
bounce?: {
|
|
252
|
+
type: 'Permanent' | 'Transient' | (string & {}) | null;
|
|
253
|
+
sub_type: string | null;
|
|
254
|
+
message: string | null;
|
|
255
|
+
};
|
|
256
|
+
complaint?: {
|
|
257
|
+
type: string | null;
|
|
258
|
+
};
|
|
259
|
+
open?: {
|
|
260
|
+
ip_address: string | null;
|
|
261
|
+
user_agent: string | null;
|
|
262
|
+
};
|
|
263
|
+
click?: {
|
|
264
|
+
link: string | null;
|
|
265
|
+
ip_address: string | null;
|
|
266
|
+
user_agent: string | null;
|
|
267
|
+
};
|
|
268
|
+
failed?: {
|
|
269
|
+
reason: string;
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
/** The event `verifyWebhook` returns. Check `event.type` and `event.data` has the matching fields. */
|
|
273
|
+
export type MailumiWebhookEvent = {
|
|
274
|
+
id: string;
|
|
275
|
+
type: 'email.received';
|
|
276
|
+
created_at: string;
|
|
277
|
+
data: EmailReceivedData;
|
|
278
|
+
} | {
|
|
279
|
+
id: string;
|
|
280
|
+
type: Exclude<WebhookEventType, 'email.received' | 'webhook.test'>;
|
|
281
|
+
created_at: string;
|
|
282
|
+
data: EmailEventData;
|
|
283
|
+
} | {
|
|
284
|
+
id: string;
|
|
285
|
+
type: 'webhook.test';
|
|
286
|
+
created_at: string;
|
|
287
|
+
data: {
|
|
288
|
+
message: string;
|
|
289
|
+
};
|
|
290
|
+
};
|
|
192
291
|
export interface VerifyWebhookOptions {
|
|
193
292
|
/** The raw request body exactly as received, before any JSON parsing. */
|
|
194
293
|
payload: string | Uint8Array;
|
|
@@ -203,7 +302,8 @@ export interface VerifyWebhookOptions {
|
|
|
203
302
|
* Checks the Standard Webhooks signature of a Mailumi webhook and returns the parsed event.
|
|
204
303
|
* Store `event.id` and skip ids you have seen: a delivery can arrive more than once.
|
|
205
304
|
*/
|
|
206
|
-
export declare function verifyWebhook
|
|
305
|
+
export declare function verifyWebhook(options: VerifyWebhookOptions): Promise<Result<MailumiWebhookEvent>>;
|
|
306
|
+
export declare function verifyWebhook<T>(options: VerifyWebhookOptions): Promise<Result<WebhookEvent<T>>>;
|
|
207
307
|
/** Converts the SDK's camelCase options to the API's request body. snake_case keys are accepted too. */
|
|
208
308
|
export declare function toApiEmail(o: SendEmailOptions & Record<string, any>): Record<string, unknown>;
|
|
209
309
|
export declare class Mailumi {
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The official Mailumi SDK. Works anywhere `fetch` exists: Node.js 18+, Bun, Deno and Cloudflare Workers.
|
|
3
3
|
* Every method resolves to `{ data, error }` and never throws for API errors.
|
|
4
4
|
*/
|
|
5
|
-
export const VERSION = '1.
|
|
5
|
+
export const VERSION = '1.1.0';
|
|
6
6
|
const DEFAULT_BASE_URL = 'https://mailumi.com/api/v1';
|
|
7
7
|
function header(h, name, short) {
|
|
8
8
|
if (typeof h.get === 'function')
|
|
@@ -24,10 +24,6 @@ function sameText(a, b) {
|
|
|
24
24
|
diff |= (a.charCodeAt(i) || 0) ^ (b.charCodeAt(i) || 0);
|
|
25
25
|
return diff === 0;
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
28
|
-
* Checks the Standard Webhooks signature of a Mailumi webhook and returns the parsed event.
|
|
29
|
-
* Store `event.id` and skip ids you have seen: a delivery can arrive more than once.
|
|
30
|
-
*/
|
|
31
27
|
export async function verifyWebhook({ payload, headers, secret, tolerance = 300 }) {
|
|
32
28
|
const key = secret ?? globalThis.process?.env?.MAILUMI_WEBHOOK_SECRET;
|
|
33
29
|
if (!key)
|
package/package.json
CHANGED