mailmark 0.1.2 → 0.1.3

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # mailmark
2
2
 
3
- Official Node.js SDK for the [DevMail](https://mailmark.io) transactional email API.
3
+ Official Node.js SDK for the [Mailmark](https://mailmark.io) transactional email API.
4
4
 
5
5
  ## Installation
6
6
 
@@ -25,41 +25,204 @@ await client.send({
25
25
  });
26
26
  ```
27
27
 
28
- ## API
28
+ ## API Reference
29
29
 
30
30
  ### `new Mailmark(apiKey, options?)`
31
31
 
32
32
  | Parameter | Type | Description |
33
33
  |-----------|------|-------------|
34
34
  | `apiKey` | `string` | Your API key from the Mailmark Developer dashboard |
35
- | `options.baseUrl` | `string` | Override the API base URL (for self-hosted) |
35
+ | `options.baseUrl` | `string` | Override the API base URL (for self-hosted instances) |
36
36
 
37
- ### `client.send(options)`
37
+ ---
38
+
39
+ ### Mailboxes
40
+
41
+ #### `client.listMailboxes()`
42
+
43
+ Returns all mailboxes on the API key's domain.
44
+
45
+ ```ts
46
+ const mailboxes = await client.listMailboxes();
47
+ // [{ id, address, fullAddress, displayName }, ...]
48
+ ```
49
+
50
+ #### `client.createMailbox(options)`
51
+
52
+ Creates a new mailbox. Pass only the local part of the address — the domain is appended automatically.
53
+
54
+ ```ts
55
+ const mailbox = await client.createMailbox({
56
+ address: 'support', // becomes support@yourdomain.com
57
+ displayName: 'Support Team',
58
+ });
59
+ ```
60
+
61
+ | Field | Type | Required | Description |
62
+ |-------|------|----------|-------------|
63
+ | `address` | `string` | Yes | Local part of the address (e.g. `support`) |
64
+ | `displayName` | `string` | No | Optional sender display name |
65
+
66
+ #### `client.deleteMailbox(address)`
67
+
68
+ Deletes a mailbox and all its emails. Pass either the local part (`"support"`) or the full address (`"support@yourdomain.com"`).
69
+
70
+ ```ts
71
+ await client.deleteMailbox('support');
72
+ ```
73
+
74
+ ---
75
+
76
+ ### Sender Groups
77
+
78
+ Sender groups define which mailboxes send to which recipient lists.
79
+
80
+ #### `client.listSenderGroups()`
81
+
82
+ Returns all sender groups on the API key's domain.
83
+
84
+ ```ts
85
+ const groups = await client.listSenderGroups();
86
+ // [{ id, name, mailboxIds, emails }, ...]
87
+ ```
88
+
89
+ #### `client.createSenderGroup(options)`
90
+
91
+ Creates a new sender group.
92
+
93
+ ```ts
94
+ const group = await client.createSenderGroup({
95
+ name: 'Newsletter',
96
+ mailboxes: 'all', // or ['hello@yourdomain.com']
97
+ emails: ['alice@example.com', 'bob@example.com'],
98
+ });
99
+ ```
100
+
101
+ | Field | Type | Required | Description |
102
+ |-------|------|----------|-------------|
103
+ | `name` | `string` | Yes | Group name |
104
+ | `mailboxes` | `string[] \| "all"` | No | Sender mailbox addresses. Defaults to `"all"` |
105
+ | `emails` | `string[]` | No | Initial recipient list |
106
+
107
+ #### `client.updateSenderGroup(id, options)`
108
+
109
+ Updates a sender group. All fields are optional.
110
+
111
+ ```ts
112
+ await client.updateSenderGroup('group_id', {
113
+ name: 'Newsletter v2',
114
+ addEmails: ['carol@example.com'],
115
+ removeEmails: ['bob@example.com'],
116
+ });
117
+ ```
118
+
119
+ | Field | Type | Description |
120
+ |-------|------|-------------|
121
+ | `name` | `string` | Rename the group |
122
+ | `emails` | `string[]` | Replace the entire recipient list |
123
+ | `addEmails` | `string[]` | Add emails to the recipient list |
124
+ | `removeEmails` | `string[]` | Remove emails from the recipient list |
125
+ | `mailboxes` | `string[] \| "all"` | Replace the sender mailbox list |
126
+
127
+ #### `client.deleteSenderGroup(id)`
128
+
129
+ Deletes a sender group by ID.
130
+
131
+ ```ts
132
+ await client.deleteSenderGroup('group_id');
133
+ ```
134
+
135
+ ---
136
+
137
+ ### Send Email
138
+
139
+ #### `client.send(options)`
140
+
141
+ Sends an email from a mailbox on the API key's domain.
142
+
143
+ ```ts
144
+ // Transactional (default) — one email to all recipients together
145
+ await client.send({
146
+ from: 'hello@yourdomain.com',
147
+ to: ['alice@example.com', 'bob@example.com'],
148
+ subject: 'Welcome',
149
+ html: '<p>Hello!</p>',
150
+ });
151
+
152
+ // Campaign — one individual email per recipient, tracked under a shared batchId
153
+ await client.send({
154
+ from: 'hello@yourdomain.com',
155
+ to: ['alice@example.com', 'bob@example.com'],
156
+ subject: 'Our newsletter',
157
+ html: '<p>This month in Mailmark...</p>',
158
+ type: 'campaign',
159
+ });
160
+
161
+ // Scheduled — send at a future time (Unix ms timestamp)
162
+ await client.send({
163
+ from: 'hello@yourdomain.com',
164
+ to: 'alice@example.com',
165
+ subject: 'Reminder',
166
+ text: 'Just a reminder!',
167
+ scheduledAt: Date.now() + 60 * 60 * 1000, // 1 hour from now
168
+ });
169
+ ```
38
170
 
39
171
  | Field | Type | Required | Description |
40
172
  |-------|------|----------|-------------|
41
- | `from` | `string` | Yes | Sender address — must belong to the API key's domain |
42
- | `to` | `string \| string[]` | Yes | Recipient address(es) |
43
- | `subject` | `string` | Yes | Email subject |
173
+ | `from` | `string` | Yes | Sender address — must be an existing mailbox on the domain |
174
+ | `to` | `string \| string[]` | Yes | One or more recipient addresses |
175
+ | `subject` | `string` | Yes | Email subject line |
44
176
  | `html` | `string` | One of | HTML email body |
45
- | `text` | `string` | One of | Plain-text body (used if html is omitted) |
177
+ | `text` | `string` | One of | Plain-text body (used when `html` is not provided) |
178
+ | `type` | `"transactional" \| "campaign"` | No | Defaults to `"transactional"` |
179
+ | `scheduledAt` | `number` | No | Future Unix ms timestamp to schedule the send |
46
180
 
47
- Returns `Promise<{ messageId: string; status: "queued" }>`.
181
+ **Returns** `Promise<SendEmailResult>`:
48
182
 
49
- Throws `MailmarkError` on API errors, with `.status` (HTTP status) and `.response` (parsed body).
183
+ | Field | Description |
184
+ |-------|-------------|
185
+ | `messageId` | Present for transactional sends |
186
+ | `messageIds` | Present for campaign sends (one per recipient) |
187
+ | `batchId` | Present for campaign sends |
188
+ | `status` | `"queued"` or `"scheduled"` |
50
189
 
51
- ## cURL Equivalent
190
+ ---
191
+
192
+ ## Error Handling
193
+
194
+ All API errors throw a `MailmarkError` with:
195
+
196
+ - `.message` — human-readable error description
197
+ - `.status` — HTTP status code
198
+ - `.response` — parsed response body
199
+
200
+ ```ts
201
+ import { Mailmark, MailmarkError } from 'mailmark';
202
+
203
+ try {
204
+ await client.send({ ... });
205
+ } catch (err) {
206
+ if (err instanceof MailmarkError) {
207
+ console.error(err.status, err.message);
208
+ }
209
+ }
210
+ ```
211
+
212
+ ---
213
+
214
+ ## cURL Reference
52
215
 
53
216
  ```bash
217
+ # List mailboxes
218
+ curl https://harmless-armadillo-386.convex.site/v1/mailboxes \
219
+ -H "Authorization: Bearer dm_live_your_key"
220
+
221
+ # Send email
54
222
  curl -X POST https://harmless-armadillo-386.convex.site/v1/send \
55
- -H "Authorization: Bearer dm_live_your_api_key" \
223
+ -H "Authorization: Bearer dm_live_your_key" \
56
224
  -H "Content-Type: application/json" \
57
- -d '{
58
- "from": "hello@yourdomain.com",
59
- "to": ["recipient@example.com"],
60
- "subject": "Hello",
61
- "html": "<p>Hello!</p>"
62
- }'
225
+ -d '{"from":"hello@yourdomain.com","to":["recipient@example.com"],"subject":"Hello","html":"<p>Hello!</p>"}'
63
226
  ```
64
227
 
65
228
  ## License
package/dist/index.d.ts CHANGED
@@ -1,5 +1,17 @@
1
+ export interface Mailbox {
2
+ id: string;
3
+ address: string;
4
+ fullAddress: string;
5
+ displayName: string | null;
6
+ }
7
+ export interface SenderGroup {
8
+ id: string;
9
+ name: string;
10
+ mailboxIds: string[];
11
+ emails: string[];
12
+ }
1
13
  export interface SendEmailOptions {
2
- /** Sender address — must be a mailbox on the API key's scoped domain. */
14
+ /** Sender address — must be an existing mailbox on the API key's domain. */
3
15
  from: string;
4
16
  /** One or more recipient addresses. */
5
17
  to: string | string[];
@@ -7,12 +19,57 @@ export interface SendEmailOptions {
7
19
  subject: string;
8
20
  /** HTML body. Either html or text (or both) is required. */
9
21
  html?: string;
10
- /** Plain-text body. Used if html is not provided. */
22
+ /** Plain-text body. Used when html is not provided. */
11
23
  text?: string;
24
+ /**
25
+ * "transactional" (default) — sends one email to all recipients.
26
+ * "campaign" — sends a separate individual email to each recipient,
27
+ * tracked under a shared batchId.
28
+ */
29
+ type?: "transactional" | "campaign";
30
+ /**
31
+ * Schedule the email for a future time.
32
+ * Unix millisecond timestamp (e.g. Date.now() + 60_000).
33
+ * Must be in the future.
34
+ */
35
+ scheduledAt?: number;
12
36
  }
13
37
  export interface SendEmailResult {
14
- messageId: string;
15
- status: "queued";
38
+ /** Present for transactional sends. */
39
+ messageId?: string;
40
+ /** Present for campaign sends (one per recipient). */
41
+ messageIds?: string[];
42
+ /** Present for campaign sends. */
43
+ batchId?: string;
44
+ status: "queued" | "scheduled";
45
+ }
46
+ export interface CreateMailboxOptions {
47
+ address: string;
48
+ displayName?: string;
49
+ }
50
+ export interface CreateSenderGroupOptions {
51
+ name: string;
52
+ /**
53
+ * Mailbox addresses to include as senders.
54
+ * Pass "all" to include every mailbox on the domain (default).
55
+ */
56
+ mailboxes?: string[] | "all";
57
+ /** Initial recipient email list. */
58
+ emails?: string[];
59
+ }
60
+ export interface UpdateSenderGroupOptions {
61
+ name?: string;
62
+ /** Replace the entire recipient list. */
63
+ emails?: string[];
64
+ /** Add emails to the recipient list (merged with existing). */
65
+ addEmails?: string[];
66
+ /** Remove emails from the recipient list. */
67
+ removeEmails?: string[];
68
+ /**
69
+ * Replace the sender mailbox list.
70
+ * Pass "all" to include every mailbox on the domain.
71
+ */
72
+ mailboxes?: string[] | "all";
16
73
  }
17
74
  export interface MailmarkOptions {
18
75
  /** Override the default API base URL. Useful for self-hosted instances. */
@@ -27,6 +84,41 @@ export declare class Mailmark {
27
84
  private readonly apiKey;
28
85
  private readonly baseUrl;
29
86
  constructor(apiKey: string, options?: MailmarkOptions);
87
+ private request;
88
+ /** List all mailboxes on the API key's domain. */
89
+ listMailboxes(): Promise<Mailbox[]>;
90
+ /**
91
+ * Create a new mailbox on the API key's domain.
92
+ * The domain suffix is appended automatically.
93
+ */
94
+ createMailbox(options: CreateMailboxOptions): Promise<Mailbox>;
95
+ /**
96
+ * Delete a mailbox and all its emails.
97
+ * Pass either the local part ("hello") or the full address ("hello@domain.com").
98
+ */
99
+ deleteMailbox(address: string): Promise<void>;
100
+ /** List all sender groups for the API key's domain. */
101
+ listSenderGroups(): Promise<SenderGroup[]>;
102
+ /**
103
+ * Create a sender group.
104
+ * Groups define which mailboxes send and which recipient emails they target.
105
+ */
106
+ createSenderGroup(options: CreateSenderGroupOptions): Promise<SenderGroup>;
107
+ /**
108
+ * Update a sender group. All fields are optional.
109
+ * Use addEmails / removeEmails for incremental changes to the recipient list,
110
+ * or emails to replace the entire list at once.
111
+ */
112
+ updateSenderGroup(id: string, options: UpdateSenderGroupOptions): Promise<SenderGroup>;
113
+ /** Delete a sender group by ID. */
114
+ deleteSenderGroup(id: string): Promise<void>;
115
+ /**
116
+ * Send an email from a mailbox on the API key's domain.
117
+ *
118
+ * - type "transactional" (default): one email to all recipients together.
119
+ * - type "campaign": one individual email per recipient, all tracked under a shared batchId.
120
+ * - scheduledAt: schedule for a future unix ms timestamp instead of sending now.
121
+ */
30
122
  send(options: SendEmailOptions): Promise<SendEmailResult>;
31
123
  }
32
124
  export default Mailmark;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,QAAQ,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,aAAc,SAAQ,KAAK;aAGpB,MAAM,EAAE,MAAM;aACd,QAAQ,EAAE,OAAO;gBAFjC,OAAO,EAAE,MAAM,EACC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,OAAO;CAKpC;AAID,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;IAMnD,IAAI,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;CAqChE;AAED,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,IAAI,CAAC,EAAE,eAAe,GAAG,UAAU,CAAC;IACpC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,kCAAkC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,GAAG,WAAW,CAAC;CAChC;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAC7B,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,6CAA6C;IAC7C,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,qBAAa,aAAc,SAAQ,KAAK;aAGpB,MAAM,EAAE,MAAM;aACd,QAAQ,EAAE,OAAO;gBAFjC,OAAO,EAAE,MAAM,EACC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,OAAO;CAKpC;AAMD,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;YAM3C,OAAO;IAyBrB,kDAAkD;IAClD,aAAa,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAInC;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC;IAK9D;;;OAGG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMnD,uDAAuD;IACvD,gBAAgB,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAI1C;;;OAGG;IACH,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,WAAW,CAAC;IAS1E;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,WAAW,CAAC;IAKtF,mCAAmC;IAC7B,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMlD;;;;;;OAMG;IACH,IAAI,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;CAoB1D;AAED,eAAe,QAAQ,CAAC"}
package/dist/index.js CHANGED
@@ -52,12 +52,58 @@ class Mailmark {
52
52
  baseUrl;
53
53
  constructor(apiKey, options = {}) {
54
54
  if (!apiKey)
55
- throw new Error("DevMail API key is required");
55
+ throw new Error("Mailmark API key is required");
56
56
  this.apiKey = apiKey;
57
57
  this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
58
58
  }
59
- async send(options) {
60
- const { from, to, subject, html, text } = options;
59
+ async request(method, path, body) {
60
+ const res = await fetch(`${this.baseUrl}${path}`, {
61
+ method,
62
+ headers: {
63
+ Authorization: `Bearer ${this.apiKey}`,
64
+ "Content-Type": "application/json"
65
+ },
66
+ ...body !== undefined ? { body: JSON.stringify(body) } : {}
67
+ });
68
+ const data = await res.json();
69
+ if (!res.ok) {
70
+ throw new MailmarkError(data.error ?? `Request failed with status ${res.status}`, res.status, data);
71
+ }
72
+ return data;
73
+ }
74
+ listMailboxes() {
75
+ return this.request("GET", "/v1/mailboxes");
76
+ }
77
+ createMailbox(options) {
78
+ if (!options.address)
79
+ throw new Error('"address" is required');
80
+ return this.request("POST", "/v1/mailboxes", options);
81
+ }
82
+ async deleteMailbox(address) {
83
+ await this.request("DELETE", `/v1/mailboxes/${encodeURIComponent(address)}`);
84
+ }
85
+ listSenderGroups() {
86
+ return this.request("GET", "/v1/sender-groups");
87
+ }
88
+ createSenderGroup(options) {
89
+ if (!options.name)
90
+ throw new Error('"name" is required');
91
+ return this.request("POST", "/v1/sender-groups", {
92
+ name: options.name,
93
+ mailboxes: options.mailboxes ?? "all",
94
+ emails: options.emails ?? []
95
+ });
96
+ }
97
+ updateSenderGroup(id, options) {
98
+ if (!id)
99
+ throw new Error('"id" is required');
100
+ return this.request("PATCH", `/v1/sender-groups/${encodeURIComponent(id)}`, options);
101
+ }
102
+ async deleteSenderGroup(id) {
103
+ await this.request("DELETE", `/v1/sender-groups/${encodeURIComponent(id)}`);
104
+ }
105
+ send(options) {
106
+ const { from, to, subject, html, text, type, scheduledAt } = options;
61
107
  if (!from)
62
108
  throw new Error('"from" is required');
63
109
  if (!to || Array.isArray(to) && to.length === 0)
@@ -66,26 +112,17 @@ class Mailmark {
66
112
  throw new Error('"subject" is required');
67
113
  if (!html && !text)
68
114
  throw new Error('Either "html" or "text" is required');
69
- const body = {
115
+ if (scheduledAt !== undefined && scheduledAt <= Date.now())
116
+ throw new Error('"scheduledAt" must be a future timestamp');
117
+ return this.request("POST", "/v1/send", {
70
118
  from,
71
119
  to: Array.isArray(to) ? to : [to],
72
120
  subject,
73
121
  ...html ? { html } : {},
74
- ...text ? { text } : {}
75
- };
76
- const res = await fetch(`${this.baseUrl}/v1/send`, {
77
- method: "POST",
78
- headers: {
79
- Authorization: `Bearer ${this.apiKey}`,
80
- "Content-Type": "application/json"
81
- },
82
- body: JSON.stringify(body)
122
+ ...text ? { text } : {},
123
+ ...type ? { type } : {},
124
+ ...scheduledAt !== undefined ? { scheduledAt } : {}
83
125
  });
84
- const data = await res.json();
85
- if (!res.ok) {
86
- throw new MailmarkError(data.error ?? `Request failed with status ${res.status}`, res.status, data);
87
- }
88
- return data;
89
126
  }
90
127
  }
91
128
  var src_default = Mailmark;
package/dist/index.mjs CHANGED
@@ -16,12 +16,58 @@ class Mailmark {
16
16
  baseUrl;
17
17
  constructor(apiKey, options = {}) {
18
18
  if (!apiKey)
19
- throw new Error("DevMail API key is required");
19
+ throw new Error("Mailmark API key is required");
20
20
  this.apiKey = apiKey;
21
21
  this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
22
22
  }
23
- async send(options) {
24
- const { from, to, subject, html, text } = options;
23
+ async request(method, path, body) {
24
+ const res = await fetch(`${this.baseUrl}${path}`, {
25
+ method,
26
+ headers: {
27
+ Authorization: `Bearer ${this.apiKey}`,
28
+ "Content-Type": "application/json"
29
+ },
30
+ ...body !== undefined ? { body: JSON.stringify(body) } : {}
31
+ });
32
+ const data = await res.json();
33
+ if (!res.ok) {
34
+ throw new MailmarkError(data.error ?? `Request failed with status ${res.status}`, res.status, data);
35
+ }
36
+ return data;
37
+ }
38
+ listMailboxes() {
39
+ return this.request("GET", "/v1/mailboxes");
40
+ }
41
+ createMailbox(options) {
42
+ if (!options.address)
43
+ throw new Error('"address" is required');
44
+ return this.request("POST", "/v1/mailboxes", options);
45
+ }
46
+ async deleteMailbox(address) {
47
+ await this.request("DELETE", `/v1/mailboxes/${encodeURIComponent(address)}`);
48
+ }
49
+ listSenderGroups() {
50
+ return this.request("GET", "/v1/sender-groups");
51
+ }
52
+ createSenderGroup(options) {
53
+ if (!options.name)
54
+ throw new Error('"name" is required');
55
+ return this.request("POST", "/v1/sender-groups", {
56
+ name: options.name,
57
+ mailboxes: options.mailboxes ?? "all",
58
+ emails: options.emails ?? []
59
+ });
60
+ }
61
+ updateSenderGroup(id, options) {
62
+ if (!id)
63
+ throw new Error('"id" is required');
64
+ return this.request("PATCH", `/v1/sender-groups/${encodeURIComponent(id)}`, options);
65
+ }
66
+ async deleteSenderGroup(id) {
67
+ await this.request("DELETE", `/v1/sender-groups/${encodeURIComponent(id)}`);
68
+ }
69
+ send(options) {
70
+ const { from, to, subject, html, text, type, scheduledAt } = options;
25
71
  if (!from)
26
72
  throw new Error('"from" is required');
27
73
  if (!to || Array.isArray(to) && to.length === 0)
@@ -30,26 +76,17 @@ class Mailmark {
30
76
  throw new Error('"subject" is required');
31
77
  if (!html && !text)
32
78
  throw new Error('Either "html" or "text" is required');
33
- const body = {
79
+ if (scheduledAt !== undefined && scheduledAt <= Date.now())
80
+ throw new Error('"scheduledAt" must be a future timestamp');
81
+ return this.request("POST", "/v1/send", {
34
82
  from,
35
83
  to: Array.isArray(to) ? to : [to],
36
84
  subject,
37
85
  ...html ? { html } : {},
38
- ...text ? { text } : {}
39
- };
40
- const res = await fetch(`${this.baseUrl}/v1/send`, {
41
- method: "POST",
42
- headers: {
43
- Authorization: `Bearer ${this.apiKey}`,
44
- "Content-Type": "application/json"
45
- },
46
- body: JSON.stringify(body)
86
+ ...text ? { text } : {},
87
+ ...type ? { type } : {},
88
+ ...scheduledAt !== undefined ? { scheduledAt } : {}
47
89
  });
48
- const data = await res.json();
49
- if (!res.ok) {
50
- throw new MailmarkError(data.error ?? `Request failed with status ${res.status}`, res.status, data);
51
- }
52
- return data;
53
90
  }
54
91
  }
55
92
  var src_default = Mailmark;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mailmark",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Official Node.js SDK for the Mailmark transactional email API",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",