@tratto/email 1.0.0 → 1.1.1
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 +29 -3
- package/dist/index.d.mts +55 -1
- package/dist/index.d.ts +55 -1
- package/dist/index.js +8 -4
- package/dist/index.mjs +8 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,6 +34,22 @@ const { id } = await tratto.emails.send({
|
|
|
34
34
|
console.log('Sent email:', id);
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
Or write the email in [emailmd](https://www.emailmd.dev/) markdown — the API
|
|
38
|
+
renders it into responsive, email-safe HTML (plus a text part) server-side:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
await tratto.emails.send({
|
|
42
|
+
from: 'Acme <hello@mail.acme.com>',
|
|
43
|
+
to: 'user@example.com',
|
|
44
|
+
subject: 'Welcome!',
|
|
45
|
+
markdown: '# Welcome, {{firstName}}\n\nGlad to have you on board.',
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`markdown` is mutually exclusive with `html`. Templates accept it too:
|
|
50
|
+
`templates.create({ name, markdown })` creates a `format: 'emailmd'` template
|
|
51
|
+
whose HTML is rendered and pinned at save time.
|
|
52
|
+
|
|
37
53
|
---
|
|
38
54
|
|
|
39
55
|
## Setup
|
|
@@ -265,6 +281,16 @@ await tratto.templates.testSend(tpl.id, 'me@example.com', { name: 'Alice' });
|
|
|
265
281
|
await tratto.templates.delete(tpl.id);
|
|
266
282
|
```
|
|
267
283
|
|
|
284
|
+
Templates created from `markdown` come back with `format: 'emailmd'`, the
|
|
285
|
+
markdown in `source`, the rendered HTML in `html`, and — when part of the
|
|
286
|
+
markdown could not be rendered — a `renderWarnings: string[]` array on the
|
|
287
|
+
template object. The field is absent when there is nothing to report:
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
const tpl = await tratto.templates.create({ name: 'Welcome', markdown: '# Hi {{name}}' });
|
|
291
|
+
if (tpl.renderWarnings?.length) console.warn(tpl.renderWarnings);
|
|
292
|
+
```
|
|
293
|
+
|
|
268
294
|
---
|
|
269
295
|
|
|
270
296
|
### Webhooks
|
|
@@ -326,7 +352,9 @@ console.log('Open rate:', summary.openRate);
|
|
|
326
352
|
const points = await tratto.analytics.getTimeseries('7d');
|
|
327
353
|
```
|
|
328
354
|
|
|
329
|
-
Supported periods: `'7d'` | `'30d'` | `'90d'
|
|
355
|
+
Supported periods: `'7d'` | `'30d'` | `'90d'` | `'180d'` | `'1y'` (default `'30d'`).
|
|
356
|
+
`'180d'` and `'1y'` read the long-term aggregate, which holds live data only:
|
|
357
|
+
they are rejected for test-mode keys. Results are cached server-side for 1 hour.
|
|
330
358
|
|
|
331
359
|
---
|
|
332
360
|
|
|
@@ -418,8 +446,6 @@ import type {
|
|
|
418
446
|
Template,
|
|
419
447
|
Webhook,
|
|
420
448
|
Domain,
|
|
421
|
-
ApiKey,
|
|
422
|
-
ApiKeyCreated,
|
|
423
449
|
AnalyticsSummary,
|
|
424
450
|
TimeseriesPoint,
|
|
425
451
|
Flow,
|
package/dist/index.d.mts
CHANGED
|
@@ -32,6 +32,12 @@ interface SendEmailParams {
|
|
|
32
32
|
to: string | string[];
|
|
33
33
|
subject: string;
|
|
34
34
|
html?: string;
|
|
35
|
+
/**
|
|
36
|
+
* emailmd markdown, rendered server-side into responsive email HTML
|
|
37
|
+
* (plus a text part). Mutually exclusive with `html` — the API rejects
|
|
38
|
+
* requests carrying both.
|
|
39
|
+
*/
|
|
40
|
+
markdown?: string;
|
|
35
41
|
text?: string;
|
|
36
42
|
cc?: string[];
|
|
37
43
|
bcc?: string[];
|
|
@@ -170,6 +176,14 @@ interface Campaign {
|
|
|
170
176
|
sentAt: string | null;
|
|
171
177
|
stats: CampaignStats;
|
|
172
178
|
createdAt: string;
|
|
179
|
+
/**
|
|
180
|
+
* The editable markdown of an emailmd campaign (its own copy — editing it
|
|
181
|
+
* never touches the template). Returned by `get()` only: `list()` omits
|
|
182
|
+
* `source` and `renderWarnings` to keep the payload small.
|
|
183
|
+
*/
|
|
184
|
+
source?: string;
|
|
185
|
+
/** Markdown that could not be rendered. Returned by `get()` only, absent when empty. */
|
|
186
|
+
renderWarnings?: string[];
|
|
173
187
|
}
|
|
174
188
|
interface CampaignStatsDetail {
|
|
175
189
|
campaignId: string;
|
|
@@ -199,6 +213,7 @@ interface ListCampaignsParams {
|
|
|
199
213
|
interface SendCampaignParams {
|
|
200
214
|
scheduledAt?: Date | string;
|
|
201
215
|
}
|
|
216
|
+
type TemplateFormat = 'html' | 'emailmd';
|
|
202
217
|
type TemplateStatus = 'draft' | 'published';
|
|
203
218
|
interface TemplateSummary {
|
|
204
219
|
id: string;
|
|
@@ -209,15 +224,29 @@ interface TemplateSummary {
|
|
|
209
224
|
updatedAt: string;
|
|
210
225
|
}
|
|
211
226
|
interface Template extends TemplateSummary {
|
|
227
|
+
/** Always the pinned, ready-to-send HTML — for emailmd templates it is derived from `source`. */
|
|
212
228
|
html: string;
|
|
229
|
+
/** 'html' for templates created before formats existed. Immutable after creation. */
|
|
230
|
+
format: TemplateFormat;
|
|
231
|
+
/** The markdown source of truth for emailmd templates. */
|
|
232
|
+
source?: string;
|
|
233
|
+
renderWarnings?: string[];
|
|
213
234
|
}
|
|
214
235
|
interface CreateTemplateParams {
|
|
215
236
|
name: string;
|
|
216
237
|
html?: string;
|
|
238
|
+
/**
|
|
239
|
+
* emailmd markdown source. Creates a `format: 'emailmd'` template whose
|
|
240
|
+
* HTML is rendered server-side at save time. Mutually exclusive with
|
|
241
|
+
* `html` — sending both (or `html` on an emailmd template) is rejected.
|
|
242
|
+
*/
|
|
243
|
+
markdown?: string;
|
|
217
244
|
}
|
|
218
245
|
interface UpdateTemplateParams {
|
|
219
246
|
name?: string;
|
|
220
247
|
html?: string;
|
|
248
|
+
/** New markdown source for an emailmd template (re-rendered at save). */
|
|
249
|
+
markdown?: string;
|
|
221
250
|
status?: TemplateStatus;
|
|
222
251
|
}
|
|
223
252
|
interface ListTemplatesParams {
|
|
@@ -285,7 +314,8 @@ interface ListDomainsParams {
|
|
|
285
314
|
after?: string;
|
|
286
315
|
limit?: number;
|
|
287
316
|
}
|
|
288
|
-
|
|
317
|
+
/** `'180d'` and `'1y'` read the long-term aggregate (live data only) and are rejected for test-mode keys. */
|
|
318
|
+
type AnalyticsPeriod = '7d' | '30d' | '90d' | '180d' | '1y';
|
|
289
319
|
interface AnalyticsSummary {
|
|
290
320
|
period: AnalyticsPeriod;
|
|
291
321
|
totalSent: number;
|
|
@@ -350,6 +380,20 @@ interface Workspace {
|
|
|
350
380
|
timezone: string;
|
|
351
381
|
locale: WorkspaceLocale;
|
|
352
382
|
plan: WorkspacePlan;
|
|
383
|
+
/** Workspace default sender, used when a send does not specify one. */
|
|
384
|
+
defaultFromName: string | null;
|
|
385
|
+
defaultFromEmail: string | null;
|
|
386
|
+
/**
|
|
387
|
+
* Tenant-hosted unsubscribe/preference page. When set, {{unsubscribe_url}}
|
|
388
|
+
* resolves here instead of the Tratto-hosted page.
|
|
389
|
+
*/
|
|
390
|
+
customUnsubscribeUrl: string | null;
|
|
391
|
+
/**
|
|
392
|
+
* Keep the "Sent using Tratto" branded footer on every HTML send even on a
|
|
393
|
+
* paid plan. On the free plan the branded footer is always applied
|
|
394
|
+
* regardless of this flag.
|
|
395
|
+
*/
|
|
396
|
+
keepTrattoBranding: boolean;
|
|
353
397
|
createdAt: string;
|
|
354
398
|
}
|
|
355
399
|
interface WorkspaceMember {
|
|
@@ -372,6 +416,16 @@ interface UpdateWorkspaceParams {
|
|
|
372
416
|
slug?: string;
|
|
373
417
|
timezone?: string;
|
|
374
418
|
locale?: WorkspaceLocale;
|
|
419
|
+
defaultFromName?: string;
|
|
420
|
+
defaultFromEmail?: string;
|
|
421
|
+
/** Set to null to clear and fall back to the Tratto-hosted page. */
|
|
422
|
+
customUnsubscribeUrl?: string | null;
|
|
423
|
+
/**
|
|
424
|
+
* Opt in to keep the branded footer on paid plans. Accepted on any plan
|
|
425
|
+
* (no effect on free, where branding is mandatory) and never auto-reset
|
|
426
|
+
* by plan changes.
|
|
427
|
+
*/
|
|
428
|
+
keepTrattoBranding?: boolean;
|
|
375
429
|
}
|
|
376
430
|
interface UpdateWorkspacePreferencesParams {
|
|
377
431
|
locale?: WorkspaceLocale;
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,12 @@ interface SendEmailParams {
|
|
|
32
32
|
to: string | string[];
|
|
33
33
|
subject: string;
|
|
34
34
|
html?: string;
|
|
35
|
+
/**
|
|
36
|
+
* emailmd markdown, rendered server-side into responsive email HTML
|
|
37
|
+
* (plus a text part). Mutually exclusive with `html` — the API rejects
|
|
38
|
+
* requests carrying both.
|
|
39
|
+
*/
|
|
40
|
+
markdown?: string;
|
|
35
41
|
text?: string;
|
|
36
42
|
cc?: string[];
|
|
37
43
|
bcc?: string[];
|
|
@@ -170,6 +176,14 @@ interface Campaign {
|
|
|
170
176
|
sentAt: string | null;
|
|
171
177
|
stats: CampaignStats;
|
|
172
178
|
createdAt: string;
|
|
179
|
+
/**
|
|
180
|
+
* The editable markdown of an emailmd campaign (its own copy — editing it
|
|
181
|
+
* never touches the template). Returned by `get()` only: `list()` omits
|
|
182
|
+
* `source` and `renderWarnings` to keep the payload small.
|
|
183
|
+
*/
|
|
184
|
+
source?: string;
|
|
185
|
+
/** Markdown that could not be rendered. Returned by `get()` only, absent when empty. */
|
|
186
|
+
renderWarnings?: string[];
|
|
173
187
|
}
|
|
174
188
|
interface CampaignStatsDetail {
|
|
175
189
|
campaignId: string;
|
|
@@ -199,6 +213,7 @@ interface ListCampaignsParams {
|
|
|
199
213
|
interface SendCampaignParams {
|
|
200
214
|
scheduledAt?: Date | string;
|
|
201
215
|
}
|
|
216
|
+
type TemplateFormat = 'html' | 'emailmd';
|
|
202
217
|
type TemplateStatus = 'draft' | 'published';
|
|
203
218
|
interface TemplateSummary {
|
|
204
219
|
id: string;
|
|
@@ -209,15 +224,29 @@ interface TemplateSummary {
|
|
|
209
224
|
updatedAt: string;
|
|
210
225
|
}
|
|
211
226
|
interface Template extends TemplateSummary {
|
|
227
|
+
/** Always the pinned, ready-to-send HTML — for emailmd templates it is derived from `source`. */
|
|
212
228
|
html: string;
|
|
229
|
+
/** 'html' for templates created before formats existed. Immutable after creation. */
|
|
230
|
+
format: TemplateFormat;
|
|
231
|
+
/** The markdown source of truth for emailmd templates. */
|
|
232
|
+
source?: string;
|
|
233
|
+
renderWarnings?: string[];
|
|
213
234
|
}
|
|
214
235
|
interface CreateTemplateParams {
|
|
215
236
|
name: string;
|
|
216
237
|
html?: string;
|
|
238
|
+
/**
|
|
239
|
+
* emailmd markdown source. Creates a `format: 'emailmd'` template whose
|
|
240
|
+
* HTML is rendered server-side at save time. Mutually exclusive with
|
|
241
|
+
* `html` — sending both (or `html` on an emailmd template) is rejected.
|
|
242
|
+
*/
|
|
243
|
+
markdown?: string;
|
|
217
244
|
}
|
|
218
245
|
interface UpdateTemplateParams {
|
|
219
246
|
name?: string;
|
|
220
247
|
html?: string;
|
|
248
|
+
/** New markdown source for an emailmd template (re-rendered at save). */
|
|
249
|
+
markdown?: string;
|
|
221
250
|
status?: TemplateStatus;
|
|
222
251
|
}
|
|
223
252
|
interface ListTemplatesParams {
|
|
@@ -285,7 +314,8 @@ interface ListDomainsParams {
|
|
|
285
314
|
after?: string;
|
|
286
315
|
limit?: number;
|
|
287
316
|
}
|
|
288
|
-
|
|
317
|
+
/** `'180d'` and `'1y'` read the long-term aggregate (live data only) and are rejected for test-mode keys. */
|
|
318
|
+
type AnalyticsPeriod = '7d' | '30d' | '90d' | '180d' | '1y';
|
|
289
319
|
interface AnalyticsSummary {
|
|
290
320
|
period: AnalyticsPeriod;
|
|
291
321
|
totalSent: number;
|
|
@@ -350,6 +380,20 @@ interface Workspace {
|
|
|
350
380
|
timezone: string;
|
|
351
381
|
locale: WorkspaceLocale;
|
|
352
382
|
plan: WorkspacePlan;
|
|
383
|
+
/** Workspace default sender, used when a send does not specify one. */
|
|
384
|
+
defaultFromName: string | null;
|
|
385
|
+
defaultFromEmail: string | null;
|
|
386
|
+
/**
|
|
387
|
+
* Tenant-hosted unsubscribe/preference page. When set, {{unsubscribe_url}}
|
|
388
|
+
* resolves here instead of the Tratto-hosted page.
|
|
389
|
+
*/
|
|
390
|
+
customUnsubscribeUrl: string | null;
|
|
391
|
+
/**
|
|
392
|
+
* Keep the "Sent using Tratto" branded footer on every HTML send even on a
|
|
393
|
+
* paid plan. On the free plan the branded footer is always applied
|
|
394
|
+
* regardless of this flag.
|
|
395
|
+
*/
|
|
396
|
+
keepTrattoBranding: boolean;
|
|
353
397
|
createdAt: string;
|
|
354
398
|
}
|
|
355
399
|
interface WorkspaceMember {
|
|
@@ -372,6 +416,16 @@ interface UpdateWorkspaceParams {
|
|
|
372
416
|
slug?: string;
|
|
373
417
|
timezone?: string;
|
|
374
418
|
locale?: WorkspaceLocale;
|
|
419
|
+
defaultFromName?: string;
|
|
420
|
+
defaultFromEmail?: string;
|
|
421
|
+
/** Set to null to clear and fall back to the Tratto-hosted page. */
|
|
422
|
+
customUnsubscribeUrl?: string | null;
|
|
423
|
+
/**
|
|
424
|
+
* Opt in to keep the branded footer on paid plans. Accepted on any plan
|
|
425
|
+
* (no effect on free, where branding is mandatory) and never auto-reset
|
|
426
|
+
* by plan changes.
|
|
427
|
+
*/
|
|
428
|
+
keepTrattoBranding?: boolean;
|
|
375
429
|
}
|
|
376
430
|
interface UpdateWorkspacePreferencesParams {
|
|
377
431
|
locale?: WorkspaceLocale;
|
package/dist/index.js
CHANGED
|
@@ -36,6 +36,9 @@ var TrattoError = class extends Error {
|
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
+
// package.json
|
|
40
|
+
var version = "1.1.1";
|
|
41
|
+
|
|
39
42
|
// src/resources/base.ts
|
|
40
43
|
var BaseResource = class {
|
|
41
44
|
constructor(apiKey, baseUrl) {
|
|
@@ -47,7 +50,7 @@ var BaseResource = class {
|
|
|
47
50
|
const contentType = options?.contentType ?? (hasBody ? "application/json" : void 0);
|
|
48
51
|
const headers = {
|
|
49
52
|
Authorization: `Bearer ${this.apiKey}`,
|
|
50
|
-
"User-Agent":
|
|
53
|
+
"User-Agent": `@tratto/email/${version}`,
|
|
51
54
|
...contentType ? { "Content-Type": contentType } : {},
|
|
52
55
|
...options?.headers
|
|
53
56
|
};
|
|
@@ -212,7 +215,8 @@ var TemplatesResource = class extends BaseResource {
|
|
|
212
215
|
return this.fetch("GET", `/v1/templates${qs}`);
|
|
213
216
|
}
|
|
214
217
|
create(params) {
|
|
215
|
-
|
|
218
|
+
const body = params.markdown !== void 0 ? { ...params, format: "emailmd" } : params;
|
|
219
|
+
return this.fetchData("POST", "/v1/templates", { body });
|
|
216
220
|
}
|
|
217
221
|
get(id) {
|
|
218
222
|
return this.fetchData("GET", `/v1/templates/${id}`);
|
|
@@ -226,8 +230,8 @@ var TemplatesResource = class extends BaseResource {
|
|
|
226
230
|
listVersions(id) {
|
|
227
231
|
return this.fetchData("GET", `/v1/templates/${id}/versions`);
|
|
228
232
|
}
|
|
229
|
-
getVersion(id,
|
|
230
|
-
return this.fetchData("GET", `/v1/templates/${id}/versions/${
|
|
233
|
+
getVersion(id, version2) {
|
|
234
|
+
return this.fetchData("GET", `/v1/templates/${id}/versions/${version2}`);
|
|
231
235
|
}
|
|
232
236
|
testSend(id, to, variables = {}) {
|
|
233
237
|
return this.fetchData(
|
package/dist/index.mjs
CHANGED
|
@@ -9,6 +9,9 @@ var TrattoError = class extends Error {
|
|
|
9
9
|
}
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// package.json
|
|
13
|
+
var version = "1.1.1";
|
|
14
|
+
|
|
12
15
|
// src/resources/base.ts
|
|
13
16
|
var BaseResource = class {
|
|
14
17
|
constructor(apiKey, baseUrl) {
|
|
@@ -20,7 +23,7 @@ var BaseResource = class {
|
|
|
20
23
|
const contentType = options?.contentType ?? (hasBody ? "application/json" : void 0);
|
|
21
24
|
const headers = {
|
|
22
25
|
Authorization: `Bearer ${this.apiKey}`,
|
|
23
|
-
"User-Agent":
|
|
26
|
+
"User-Agent": `@tratto/email/${version}`,
|
|
24
27
|
...contentType ? { "Content-Type": contentType } : {},
|
|
25
28
|
...options?.headers
|
|
26
29
|
};
|
|
@@ -185,7 +188,8 @@ var TemplatesResource = class extends BaseResource {
|
|
|
185
188
|
return this.fetch("GET", `/v1/templates${qs}`);
|
|
186
189
|
}
|
|
187
190
|
create(params) {
|
|
188
|
-
|
|
191
|
+
const body = params.markdown !== void 0 ? { ...params, format: "emailmd" } : params;
|
|
192
|
+
return this.fetchData("POST", "/v1/templates", { body });
|
|
189
193
|
}
|
|
190
194
|
get(id) {
|
|
191
195
|
return this.fetchData("GET", `/v1/templates/${id}`);
|
|
@@ -199,8 +203,8 @@ var TemplatesResource = class extends BaseResource {
|
|
|
199
203
|
listVersions(id) {
|
|
200
204
|
return this.fetchData("GET", `/v1/templates/${id}/versions`);
|
|
201
205
|
}
|
|
202
|
-
getVersion(id,
|
|
203
|
-
return this.fetchData("GET", `/v1/templates/${id}/versions/${
|
|
206
|
+
getVersion(id, version2) {
|
|
207
|
+
return this.fetchData("GET", `/v1/templates/${id}/versions/${version2}`);
|
|
204
208
|
}
|
|
205
209
|
testSend(id, to, variables = {}) {
|
|
206
210
|
return this.fetchData(
|