@framers/agentos-ext-channel-email 0.1.1 → 0.2.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 +104 -0
- package/dist/EmailChannelAdapter.d.ts +6 -0
- package/dist/EmailChannelAdapter.d.ts.map +1 -1
- package/dist/EmailChannelAdapter.js +9 -0
- package/dist/EmailChannelAdapter.js.map +1 -1
- package/dist/EmailService.d.ts +30 -3
- package/dist/EmailService.d.ts.map +1 -1
- package/dist/EmailService.js +71 -14
- package/dist/EmailService.js.map +1 -1
- package/dist/ResendTransport.d.ts +101 -0
- package/dist/ResendTransport.d.ts.map +1 -0
- package/dist/ResendTransport.js +194 -0
- package/dist/ResendTransport.js.map +1 -0
- package/dist/agentAttachments.d.ts +23 -0
- package/dist/agentAttachments.d.ts.map +1 -0
- package/dist/agentAttachments.js +50 -0
- package/dist/agentAttachments.js.map +1 -0
- package/dist/index.d.ts +16 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -12
- package/dist/index.js.map +1 -1
- package/dist/tools/send.d.ts +9 -1
- package/dist/tools/send.d.ts.map +1 -1
- package/dist/tools/send.js +9 -2
- package/dist/tools/send.js.map +1 -1
- package/manifest.json +4 -4
- package/package.json +12 -7
package/README.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# @framers/agentos-ext-channel-email
|
|
2
|
+
|
|
3
|
+
Email for AgentOS. `EmailService` sends mail through SMTP or Resend's HTTPS API, and reads, searches, extracts codes from and replies to mail through IMAP. The pack's factory wraps the service in a messaging-channel adapter and five tools for an agent.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @framers/agentos-ext-channel-email
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
It needs Node.js 20 or later, the floor of nodemailer 10. Its runtime dependencies are [nodemailer](https://github.com/nodemailer/nodemailer) for SMTP and [imapflow](https://github.com/postalsys/imapflow) for IMAP. `@framers/agentos` is an optional peer, needed only when an agent loads the pack: nothing in the pack imports it, so `EmailService` works without it.
|
|
12
|
+
|
|
13
|
+
## Sending through SMTP
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { EmailService } from '@framers/agentos-ext-channel-email';
|
|
17
|
+
|
|
18
|
+
const email = new EmailService({
|
|
19
|
+
smtp: { host: 'smtp.example.com', user: 'hello@example.com', password: process.env.SMTP_PASSWORD ?? '' },
|
|
20
|
+
from: 'Example <hello@example.com>',
|
|
21
|
+
});
|
|
22
|
+
await email.initialize();
|
|
23
|
+
await email.sendEmail({ to: 'reader@example.com', subject: 'Hello', body: 'Plain words.', html: '<p>Plain words.</p>' });
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`smtp` takes `host`, `user` and `password`, with `port` and `secure`: by default the connection uses TLS on port 465, and `secure: false` moves the default port to 587. `initialize()` checks the connection, and a failed check is not an error. The pack's factory reads the account from the secrets `email.smtpHost`, `email.smtpUser` and `email.smtpPassword`, or from `SMTP_HOST`, `SMTP_USER` and `SMTP_PASSWORD`.
|
|
27
|
+
|
|
28
|
+
## Sending through Resend
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { EmailService } from '@framers/agentos-ext-channel-email';
|
|
32
|
+
|
|
33
|
+
const email = new EmailService({
|
|
34
|
+
resend: { apiKey: process.env.RESEND_API_KEY ?? '' },
|
|
35
|
+
from: 'Example <hello@example.com>',
|
|
36
|
+
});
|
|
37
|
+
await email.initialize();
|
|
38
|
+
const { messageId } = await email.sendEmail({
|
|
39
|
+
to: 'reader@example.com',
|
|
40
|
+
subject: 'Hello',
|
|
41
|
+
body: 'Plain words.',
|
|
42
|
+
html: '<p>Plain words.</p>',
|
|
43
|
+
replyTo: 'team@example.com',
|
|
44
|
+
idempotencyKey: 'welcome-reader-1',
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Each message goes out as `POST /emails` with the key as the bearer and the text and HTML parts in the same call, and `messageId` is the id Resend gives the email, or the empty string when an accepted answer names none or its body cannot be read: a 2xx means the email was sent, so the send never fails after one. A refusal that is tried again repeats the same request, with the same key and any `Idempotency-Key`, so one send makes at most `maxRetries + 1` requests. `idempotencyKey` is sent as Resend's `Idempotency-Key` header: another request under the same key within 24 hours delivers nothing more ([idempotency keys](https://resend.com/docs/dashboard/emails/idempotency-keys)). Keep it to 256 characters at most and free of personal data. SMTP ignores it.
|
|
49
|
+
|
|
50
|
+
Attachments take a `filename` with `content` (a string or a Buffer, sent as Base64) or a `path`. Through Resend, an `http` or `https` path is the address Resend fetches the file from, and a `data:` address or a file on this host is read by the transport and sent as content, as nodemailer reads both over SMTP; when `content` is given too, such a path is left out. A file that cannot be read throws its own error before any request. Through either transport `sendEmail` reads a file on this host, and through SMTP it fetches an `http` or `https` address, from this process: such a path must come from the developer's code and never from a model's output. The `emailSend` tool and the channel adapter take only `content`, a `data:` address and, through Resend, an `http` or `https` address.
|
|
51
|
+
|
|
52
|
+
| `resend` option | Default | What it sets |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `apiKey` | required | The API key, or a function that returns it at each send, so a rotated key applies without a restart |
|
|
55
|
+
| `baseUrl` | `https://api.resend.com` | The API's origin, such as a proxy's or a test server's |
|
|
56
|
+
| `userAgent` | `agentos-ext-channel-email` | The `User-Agent` of every request; Resend refuses a request without one |
|
|
57
|
+
| `timeoutMs` | 15,000 | The longest one send may take, its retries and their waits included |
|
|
58
|
+
| `maxRetries` | 2 | The most retries one send makes |
|
|
59
|
+
|
|
60
|
+
The pack's factory sends through Resend when it has a Resend key and no SMTP host: the option `resendApiKey`, the secret `email.resendApiKey` or `RESEND_API_KEY`, with `resendBaseUrl` for the origin. Given an SMTP host, it keeps SMTP.
|
|
61
|
+
|
|
62
|
+
## The From
|
|
63
|
+
|
|
64
|
+
`from` sets the From header of both transports, and a display name is allowed (`Example <hello@example.com>`). With SMTP it falls back to the SMTP user; with Resend it is required, and `initialize()` throws without it. Replies are sent from it too. The pack's factory reads it from the option `from`, then from `EMAIL_FROM`.
|
|
65
|
+
|
|
66
|
+
## Errors and retries
|
|
67
|
+
|
|
68
|
+
A refusal from Resend throws `EmailApiError`, with `status` (the HTTP status), `type` (Resend's error name, such as `validation_error`, or `unknown` when the answer's body is not JSON, names no error, or names one that is not 1 to 64 letters, digits, `_`, `.`, `:` or `-`) and `retryAfterSeconds` (the answer's `retry-after`, or `null`). Its message names the status and the type and never carries Resend's message, which can quote an address.
|
|
69
|
+
|
|
70
|
+
`fetch`'s own errors pass through as it throws them: a `TypeError` when the connection fails, and a `TimeoutError` when `timeoutMs` passes before an answer comes. A deadline that passes while an answer's body is being read throws no `TimeoutError`: a refusal then throws `EmailApiError` with `type` `unknown`, and an accepted send resolves with an empty `messageId`. The key is trimmed at each send. A key, an `idempotencyKey` or a `userAgent` that holds a character an HTTP header cannot carry (a line break or another control character other than a tab, or a character above U+00FF) throws an `Error` before any request, and its message names which one and none of its value.
|
|
71
|
+
|
|
72
|
+
A send is tried again only on the terms of Resend's [errors](https://resend.com/docs/api-reference/errors) and [rate limit](https://resend.com/docs/api-reference/rate-limit) pages, as `retryWaitSeconds` decides:
|
|
73
|
+
|
|
74
|
+
- `rate_limit_exceeded` (429): always, since nothing was sent;
|
|
75
|
+
- `concurrent_idempotent_requests` (409) and any 5xx, such as `application_error` (500) and `service_unavailable` (503): only when the send has an `idempotencyKey`, so a retry cannot deliver twice;
|
|
76
|
+
- never `daily_quota_exceeded` or `monthly_quota_exceeded` (both 429), `validation_error`, `invalid_idempotent_request` or any other 4xx.
|
|
77
|
+
|
|
78
|
+
The wait is the answer's `retry-after` when it has one, else as many seconds as the retry's number: one, then two. A send makes at most `maxRetries` retries, and a wait that would pass the deadline is not taken: the refusal is thrown instead.
|
|
79
|
+
|
|
80
|
+
## Reading mail
|
|
81
|
+
|
|
82
|
+
`readInbox`, `searchEmails`, `extractCodes` and `replyToEmail` read through IMAP: the `imap` account (`host`, `user` and `password`, with `port` and `secure`, by default TLS on port 993), or the SMTP account when `imap` is not given. With Resend, reading needs `imap`. A reply goes out through the transport that sends, threaded with `In-Reply-To` and `References`. The pack's factory reads the account from the secrets `email.imap.host`, `email.imap.user` and `email.imap.password`, or from `IMAP_HOST`, `IMAP_USER` and `IMAP_PASSWORD`.
|
|
83
|
+
|
|
84
|
+
## In an agent
|
|
85
|
+
|
|
86
|
+
`createExtensionPack(context)` returns five tools, `emailSend`, `emailRead`, `emailSearch`, `emailExtractCodes` and `emailReply`, and the messaging channel `emailChannel`. Its options (`smtpHost`, `smtpUser`, `smtpPassword`, `smtpPort`, `smtpSecure`, `imapHost`, `imapUser`, `imapPassword`, `imapPort`, `imapSecure`, `resendApiKey`, `resendBaseUrl`, `from`) take precedence over the secrets and the environment variables named above. `manifest.json` lists the SMTP secrets as required, and the IMAP secrets and `email.resendApiKey` as optional.
|
|
87
|
+
|
|
88
|
+
A model names the tools' arguments and the channel's blocks, so `emailSend` and `emailChannel` pass on an attachment only as `content`, a `data:` address or, through Resend, an `http` or `https` address. They refuse any other before anything is sent, reading no file and fetching no address: the tool answers `{ success: false, error }`, the adapter throws an `Error`, and the message names the attachment's filename, never its path.
|
|
89
|
+
|
|
90
|
+
## API
|
|
91
|
+
|
|
92
|
+
| Export | What it is |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `createExtensionPack(context)` | The pack's factory: the five tools and the channel adapter |
|
|
95
|
+
| `EmailService` | Sends through SMTP or Resend's HTTPS API; reads, searches, extracts codes and replies through IMAP |
|
|
96
|
+
| `ResendTransport` | Resend's send call, which `EmailService` uses when its configuration names `resend` |
|
|
97
|
+
| `EmailApiError`, `retryWaitSeconds` | A refusal from Resend, and the wait before its retry (`null` for none) |
|
|
98
|
+
| `EmailChannelAdapter` | The messaging-channel adapter |
|
|
99
|
+
| `EmailSendTool`, `EmailReadTool`, `EmailSearchTool`, `EmailExtractCodesTool`, `EmailReplyTool` | The five tools |
|
|
100
|
+
| `EmailConfig`, `SendEmailOptions`, `EmailMessage`, `SearchEmailOptions`, `ResendOptions`, `OutgoingEmail`, `OutgoingAttachment`, `EmailChannelOptions`, `ExtensionContext`, `ExtensionPack` | The types of the configuration, the messages, the options and the pack |
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
Apache-2.0
|
|
@@ -42,6 +42,12 @@ export declare class EmailChannelAdapter {
|
|
|
42
42
|
initialize(_auth: ChannelAuthConfig): Promise<void>;
|
|
43
43
|
shutdown(): Promise<void>;
|
|
44
44
|
getConnectionInfo(): ChannelConnectionInfo;
|
|
45
|
+
/**
|
|
46
|
+
* Sends `content` to `conversationId`, or replies when it names `replyToMessageId` (a reply carries no attachments).
|
|
47
|
+
* Its `document` and `image` blocks become attachments, each with the block's `content` or its `url` as the path, and
|
|
48
|
+
* one that is not `content`, a `data:` address or, through Resend, an `http(s)` address throws an `Error` naming its
|
|
49
|
+
* filename before anything is sent, a reply included.
|
|
50
|
+
*/
|
|
45
51
|
sendMessage(conversationId: string, content: MessageContent): Promise<ChannelSendResult>;
|
|
46
52
|
sendTypingIndicator(_conversationId: string, _isTyping: boolean): Promise<void>;
|
|
47
53
|
on(handler: ChannelEventHandler, _eventTypes?: ChannelEventType[]): () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmailChannelAdapter.d.ts","sourceRoot":"","sources":["../src/EmailChannelAdapter.ts"],"names":[],"mappings":"AACA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"EmailChannelAdapter.d.ts","sourceRoot":"","sources":["../src/EmailChannelAdapter.ts"],"names":[],"mappings":"AACA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGtD,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC;AACrC,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACvC,MAAM,MAAM,uBAAuB,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,GAAG,OAAO,CAAC;AAC7G,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEtC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,eAAe,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,uBAAuB,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC,CAAC;IACpD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEvE,qBAAa,mBAAmB;IAC9B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAW;IAC7C,QAAQ,CAAC,WAAW,WAAW;IAC/B,QAAQ,CAAC,YAAY,EAAE,SAAS,iBAAiB,EAAE,CAEjD;IAEF,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,QAAQ,CAAuC;IACvD,OAAO,CAAC,YAAY,CAAuB;gBAE/B,OAAO,EAAE,YAAY;IAI3B,UAAU,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAWnD,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAK/B,iBAAiB,IAAI,qBAAqB;IAc1C;;;;;OAKG;IACG,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAwCxF,mBAAmB,CAAC,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrF,EAAE,CAAC,OAAO,EAAE,mBAAmB,EAAE,WAAW,CAAC,EAAE,gBAAgB,EAAE,GAAG,MAAM,IAAI;CAI/E"}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.EmailChannelAdapter = void 0;
|
|
8
|
+
const agentAttachments_js_1 = require("./agentAttachments.js");
|
|
8
9
|
class EmailChannelAdapter {
|
|
9
10
|
constructor(service) {
|
|
10
11
|
this.platform = 'email';
|
|
@@ -45,6 +46,12 @@ class EmailChannelAdapter {
|
|
|
45
46
|
platformInfo: { platform: 'email' },
|
|
46
47
|
};
|
|
47
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Sends `content` to `conversationId`, or replies when it names `replyToMessageId` (a reply carries no attachments).
|
|
51
|
+
* Its `document` and `image` blocks become attachments, each with the block's `content` or its `url` as the path, and
|
|
52
|
+
* one that is not `content`, a `data:` address or, through Resend, an `http(s)` address throws an `Error` naming its
|
|
53
|
+
* filename before anything is sent, a reply included.
|
|
54
|
+
*/
|
|
48
55
|
async sendMessage(conversationId, content) {
|
|
49
56
|
const textBlock = content.blocks.find((b) => b.type === 'text');
|
|
50
57
|
const htmlBlock = content.blocks.find((b) => b.type === 'rich_text' || b.type === 'html');
|
|
@@ -63,6 +70,8 @@ class EmailChannelAdapter {
|
|
|
63
70
|
});
|
|
64
71
|
}
|
|
65
72
|
}
|
|
73
|
+
// A model writes these blocks: an attachment this process would read or fetch stops the message here.
|
|
74
|
+
(0, agentAttachments_js_1.requireAgentAttachments)(attachments, this.service.transport === 'resend');
|
|
66
75
|
if (content.replyToMessageId) {
|
|
67
76
|
const result = await this.service.replyToEmail(content.replyToMessageId, text, html);
|
|
68
77
|
return { messageId: result.messageId, timestamp: new Date().toISOString() };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmailChannelAdapter.js","sourceRoot":"","sources":["../src/EmailChannelAdapter.ts"],"names":[],"mappings":";AAAA,cAAc;AACd;;GAEG;;;
|
|
1
|
+
{"version":3,"file":"EmailChannelAdapter.js","sourceRoot":"","sources":["../src/EmailChannelAdapter.ts"],"names":[],"mappings":"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"}
|
package/dist/EmailService.d.ts
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Email service layer.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Sends through nodemailer (SMTP) or Resend's HTTPS API, and reads,
|
|
5
|
+
* searches, and fetches the messages it replies to through imapflow (IMAP).
|
|
6
6
|
*/
|
|
7
|
+
import type { ResendOptions } from './ResendTransport.js';
|
|
8
|
+
/** The accounts the service uses: an SMTP account or Resend's HTTPS API to send, and IMAP to read. */
|
|
7
9
|
export interface EmailConfig {
|
|
8
|
-
|
|
10
|
+
/** The SMTP account that sends, and reads when `imap` is not given. Required unless `resend` is given. */
|
|
11
|
+
smtp?: {
|
|
9
12
|
host: string;
|
|
10
13
|
user: string;
|
|
11
14
|
password: string;
|
|
12
15
|
port?: number;
|
|
13
16
|
secure?: boolean;
|
|
14
17
|
};
|
|
18
|
+
/** Resend's HTTPS API in place of SMTP for sending; reading mail still needs `imap`. */
|
|
19
|
+
resend?: ResendOptions;
|
|
20
|
+
/** The From header, a display name allowed ("Example <hello@example.com>"); the SMTP user when unset. Required with `resend`. */
|
|
21
|
+
from?: string;
|
|
15
22
|
imap?: {
|
|
16
23
|
host: string;
|
|
17
24
|
user: string;
|
|
@@ -34,6 +41,8 @@ export interface SendEmailOptions {
|
|
|
34
41
|
replyTo?: string;
|
|
35
42
|
cc?: string;
|
|
36
43
|
bcc?: string;
|
|
44
|
+
/** Resend's Idempotency-Key for this message; SMTP ignores it. */
|
|
45
|
+
idempotencyKey?: string;
|
|
37
46
|
}
|
|
38
47
|
export interface EmailMessage {
|
|
39
48
|
messageId: string;
|
|
@@ -55,11 +64,29 @@ export interface SearchEmailOptions {
|
|
|
55
64
|
export declare class EmailService {
|
|
56
65
|
private config;
|
|
57
66
|
private transporter;
|
|
67
|
+
private resend;
|
|
58
68
|
private running;
|
|
59
69
|
constructor(config: EmailConfig);
|
|
70
|
+
/**
|
|
71
|
+
* Opens the transport that sends: Resend's API when `resend` is given (`from` is then required), else the SMTP
|
|
72
|
+
* account. Throws an `Error` before opening anything when the configuration gives neither `resend` nor `smtp`.
|
|
73
|
+
*/
|
|
60
74
|
initialize(): Promise<void>;
|
|
61
75
|
shutdown(): Promise<void>;
|
|
62
76
|
get isRunning(): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* The transport that sends: `'resend'` or `'smtp'` once `initialize()` has opened it, `null` before that and after
|
|
79
|
+
* `shutdown()`. The `emailSend` tool and the channel adapter read it to tell which attachments they may pass on.
|
|
80
|
+
*/
|
|
81
|
+
get transport(): 'resend' | 'smtp' | null;
|
|
82
|
+
/**
|
|
83
|
+
* Sends one message through the transport `initialize()` opened and resolves with the id it gives. An attachment's
|
|
84
|
+
* `path` may be a file on this host, which this process reads through either transport, or an `http:` or `https:`
|
|
85
|
+
* address, which this process fetches through SMTP (through Resend, Resend's servers fetch it): such a path must come
|
|
86
|
+
* from the developer's code and never from a model's output. The `emailSend` tool and the channel adapter accept only
|
|
87
|
+
* `content`, `data:` addresses and, through Resend, `http(s)` addresses, and refuse any other attachment before
|
|
88
|
+
* sending.
|
|
89
|
+
*/
|
|
63
90
|
sendEmail(options: SendEmailOptions): Promise<{
|
|
64
91
|
messageId: string;
|
|
65
92
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmailService.d.ts","sourceRoot":"","sources":["../src/EmailService.ts"],"names":[],"mappings":"AACA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"EmailService.d.ts","sourceRoot":"","sources":["../src/EmailService.ts"],"names":[],"mappings":"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"}
|
package/dist/EmailService.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @fileoverview Email service layer.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Sends through nodemailer (SMTP) or Resend's HTTPS API, and reads,
|
|
7
|
+
* searches, and fetches the messages it replies to through imapflow (IMAP).
|
|
8
8
|
*/
|
|
9
9
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
10
|
if (k2 === undefined) k2 = k;
|
|
@@ -43,16 +43,31 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
43
43
|
exports.EmailService = void 0;
|
|
44
44
|
const nodemailer = __importStar(require("nodemailer"));
|
|
45
45
|
const imapflow_1 = require("imapflow");
|
|
46
|
+
const ResendTransport_js_1 = require("./ResendTransport.js");
|
|
46
47
|
// ---------------------------------------------------------------------------
|
|
47
48
|
// Service
|
|
48
49
|
// ---------------------------------------------------------------------------
|
|
49
50
|
class EmailService {
|
|
50
51
|
constructor(config) {
|
|
51
52
|
this.transporter = null;
|
|
53
|
+
this.resend = null;
|
|
52
54
|
this.running = false;
|
|
53
55
|
this.config = config;
|
|
54
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Opens the transport that sends: Resend's API when `resend` is given (`from` is then required), else the SMTP
|
|
59
|
+
* account. Throws an `Error` before opening anything when the configuration gives neither `resend` nor `smtp`.
|
|
60
|
+
*/
|
|
55
61
|
async initialize() {
|
|
62
|
+
if (this.config.resend) {
|
|
63
|
+
if (!this.config.from)
|
|
64
|
+
throw new Error('A From address is required to send through Resend');
|
|
65
|
+
this.resend = new ResendTransport_js_1.ResendTransport(this.config.resend);
|
|
66
|
+
this.running = true;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!this.config.smtp)
|
|
70
|
+
throw new Error('Sending mail needs an SMTP account or a Resend key');
|
|
56
71
|
// Set up SMTP transporter
|
|
57
72
|
this.transporter = nodemailer.createTransport({
|
|
58
73
|
host: this.config.smtp.host,
|
|
@@ -77,18 +92,50 @@ class EmailService {
|
|
|
77
92
|
this.transporter.close();
|
|
78
93
|
this.transporter = null;
|
|
79
94
|
}
|
|
95
|
+
this.resend = null;
|
|
80
96
|
this.running = false;
|
|
81
97
|
}
|
|
82
98
|
get isRunning() {
|
|
83
99
|
return this.running;
|
|
84
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* The transport that sends: `'resend'` or `'smtp'` once `initialize()` has opened it, `null` before that and after
|
|
103
|
+
* `shutdown()`. The `emailSend` tool and the channel adapter read it to tell which attachments they may pass on.
|
|
104
|
+
*/
|
|
105
|
+
get transport() {
|
|
106
|
+
if (this.resend)
|
|
107
|
+
return 'resend';
|
|
108
|
+
return this.transporter ? 'smtp' : null;
|
|
109
|
+
}
|
|
85
110
|
// ── Send Email ──
|
|
111
|
+
/**
|
|
112
|
+
* Sends one message through the transport `initialize()` opened and resolves with the id it gives. An attachment's
|
|
113
|
+
* `path` may be a file on this host, which this process reads through either transport, or an `http:` or `https:`
|
|
114
|
+
* address, which this process fetches through SMTP (through Resend, Resend's servers fetch it): such a path must come
|
|
115
|
+
* from the developer's code and never from a model's output. The `emailSend` tool and the channel adapter accept only
|
|
116
|
+
* `content`, `data:` addresses and, through Resend, `http(s)` addresses, and refuse any other attachment before
|
|
117
|
+
* sending.
|
|
118
|
+
*/
|
|
86
119
|
async sendEmail(options) {
|
|
87
120
|
this.requireRunning();
|
|
121
|
+
if (this.resend) {
|
|
122
|
+
return this.resend.send({
|
|
123
|
+
from: this.config.from,
|
|
124
|
+
to: options.to,
|
|
125
|
+
subject: options.subject,
|
|
126
|
+
text: options.body,
|
|
127
|
+
html: options.html,
|
|
128
|
+
replyTo: options.replyTo,
|
|
129
|
+
cc: options.cc,
|
|
130
|
+
bcc: options.bcc,
|
|
131
|
+
idempotencyKey: options.idempotencyKey,
|
|
132
|
+
attachments: options.attachments,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
88
135
|
if (!this.transporter)
|
|
89
136
|
throw new Error('SMTP transporter not initialized');
|
|
90
137
|
const info = await this.transporter.sendMail({
|
|
91
|
-
from: this.config.smtp.user,
|
|
138
|
+
from: this.config.from ?? this.config.smtp.user,
|
|
92
139
|
to: options.to,
|
|
93
140
|
subject: options.subject,
|
|
94
141
|
text: options.body,
|
|
@@ -260,13 +307,13 @@ class EmailService {
|
|
|
260
307
|
// ── Reply to Email ──
|
|
261
308
|
async replyToEmail(messageId, body, html) {
|
|
262
309
|
this.requireRunning();
|
|
263
|
-
if (!this.transporter)
|
|
264
|
-
throw new Error('
|
|
310
|
+
if (!this.transporter && !this.resend)
|
|
311
|
+
throw new Error('No transport initialized');
|
|
265
312
|
// Fetch the original message to get reply headers
|
|
266
313
|
const client = await this.getImapClient();
|
|
267
314
|
let originalFrom = '';
|
|
268
315
|
let originalSubject = '';
|
|
269
|
-
let
|
|
316
|
+
let previous = '';
|
|
270
317
|
try {
|
|
271
318
|
const lock = await client.getMailboxLock('INBOX');
|
|
272
319
|
try {
|
|
@@ -278,7 +325,7 @@ class EmailService {
|
|
|
278
325
|
originalSubject = msg.envelope?.subject ?? '';
|
|
279
326
|
const headersStr = msg.headers?.toString() ?? '';
|
|
280
327
|
const refsMatch = headersStr.match(/References:\s*(.+)/i);
|
|
281
|
-
|
|
328
|
+
previous = refsMatch ? refsMatch[1].trim() : '';
|
|
282
329
|
}
|
|
283
330
|
}
|
|
284
331
|
}
|
|
@@ -290,24 +337,34 @@ class EmailService {
|
|
|
290
337
|
await client.logout();
|
|
291
338
|
}
|
|
292
339
|
const replySubject = originalSubject.startsWith('Re:') ? originalSubject : `Re: ${originalSubject}`;
|
|
340
|
+
const references = previous ? `${previous} ${messageId}` : messageId;
|
|
341
|
+
if (this.resend) {
|
|
342
|
+
return this.resend.send({
|
|
343
|
+
from: this.config.from,
|
|
344
|
+
to: originalFrom,
|
|
345
|
+
subject: replySubject,
|
|
346
|
+
text: body,
|
|
347
|
+
html,
|
|
348
|
+
headers: { 'In-Reply-To': messageId, References: references },
|
|
349
|
+
});
|
|
350
|
+
}
|
|
293
351
|
const info = await this.transporter.sendMail({
|
|
294
|
-
from: this.config.smtp.user,
|
|
352
|
+
from: this.config.from ?? this.config.smtp.user,
|
|
295
353
|
to: originalFrom,
|
|
296
354
|
subject: replySubject,
|
|
297
355
|
text: body,
|
|
298
356
|
html,
|
|
299
357
|
inReplyTo: messageId,
|
|
300
|
-
references
|
|
358
|
+
references,
|
|
301
359
|
});
|
|
302
360
|
return { messageId: info.messageId };
|
|
303
361
|
}
|
|
304
362
|
// ── Private: IMAP Client ──
|
|
305
363
|
async getImapClient() {
|
|
306
|
-
const imapConfig = this.config.imap ??
|
|
307
|
-
host: this.config.smtp.host,
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
};
|
|
364
|
+
const imapConfig = this.config.imap ??
|
|
365
|
+
(this.config.smtp ? { host: this.config.smtp.host, user: this.config.smtp.user, password: this.config.smtp.password } : undefined);
|
|
366
|
+
if (!imapConfig)
|
|
367
|
+
throw new Error('Reading mail needs an IMAP account');
|
|
311
368
|
const client = new imapflow_1.ImapFlow({
|
|
312
369
|
host: imapConfig.host,
|
|
313
370
|
port: imapConfig.port ?? 993,
|
package/dist/EmailService.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmailService.js","sourceRoot":"","sources":["../src/EmailService.ts"],"names":[],"mappings":";AAAA,cAAc;AACd;;;;;GAKG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,uDAAyC;AACzC,uCAAoC;AA0DpC,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,MAAa,YAAY;IAKvB,YAAY,MAAmB;QAHvB,gBAAW,GAAkC,IAAI,CAAC;QAClD,YAAO,GAAG,KAAK,CAAC;QAGtB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,UAAU;QACd,0BAA0B;QAC1B,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC,eAAe,CAAC;YAC5C,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;YAC3B,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;YAC9E,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,KAAK;YACzC,IAAI,EAAE;gBACJ,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;gBAC3B,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ;aAChC;SACF,CAAC,CAAC;QAEH,yBAAyB;QACzB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;QACvE,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QAC1B,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,mBAAmB;IAEnB,KAAK,CAAC,SAAS,CAAC,OAAyB;QACvC,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAE3E,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;YAC3C,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;YAC3B,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC5C,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,WAAW,EAAE,CAAC,CAAC,WAAW;aAC3B,CAAC,CAAC;SACJ,CAAC,CAAC;QAEH,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;IACvC,CAAC;IAED,mBAAmB;IAEnB,KAAK,CAAC,SAAS,CAAC,SAAiB,OAAO,EAAE,QAAgB,EAAE;QAC1D,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAE1C,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YACjD,MAAM,QAAQ,GAAmB,EAAE,CAAC;YAEpC,IAAI,CAAC;gBACH,iCAAiC;gBACjC,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBACjE,IAAI,aAAa,KAAK,CAAC;oBAAE,OAAO,EAAE,CAAC;gBAEnC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC;gBAExD,IAAI,KAAK,EAAE,MAAM,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,IAAI,EAAE;oBACpD,QAAQ,EAAE,IAAI;oBACd,MAAM,EAAE,IAAI;oBACZ,KAAK,EAAE,IAAI;oBACX,GAAG,EAAE,IAAI;iBACV,CAAC,EAAE,CAAC;oBACH,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;oBAC9B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;oBAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;oBAE/C,QAAQ,CAAC,IAAI,CAAC;wBACZ,SAAS,EAAE,QAAQ,EAAE,SAAS,IAAI,EAAE;wBACpC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE;wBACxC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE;wBACpC,OAAO,EAAE,QAAQ,EAAE,OAAO,IAAI,EAAE;wBAChC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE;wBACzC,IAAI,EAAE,QAAQ;wBACd,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;wBAClC,GAAG,EAAE,GAAG,CAAC,GAAG;qBACb,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,CAAC;YAED,OAAO,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,oBAAoB;QACjD,CAAC;gBAAS,CAAC;YACT,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IAED,sBAAsB;IAEtB,KAAK,CAAC,YAAY,CAAC,OAA2B;QAC5C,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC;QAEzC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YACjD,MAAM,QAAQ,GAAmB,EAAE,CAAC;YAEpC,IAAI,CAAC;gBACH,MAAM,cAAc,GAAQ,EAAE,CAAC;gBAE/B,6BAA6B;gBAC7B,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;oBAClB,cAAc,CAAC,EAAE,GAAG;wBAClB,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE;wBAC1B,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE;wBACvB,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE;qBACxB,CAAC;gBACJ,CAAC;gBACD,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;oBAClB,cAAc,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBACjD,CAAC;gBAED,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;gBAChE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChD,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;gBAE1D,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC3B,IAAI,KAAK,EAAE,MAAM,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE;wBAChD,QAAQ,EAAE,IAAI;wBACd,MAAM,EAAE,IAAI;wBACZ,KAAK,EAAE,IAAI;wBACX,GAAG,EAAE,IAAI;qBACV,CAAC,EAAE,CAAC;wBACH,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;wBAC9B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;wBAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;wBAE/C,QAAQ,CAAC,IAAI,CAAC;4BACZ,SAAS,EAAE,QAAQ,EAAE,SAAS,IAAI,EAAE;4BACpC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE;4BACxC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE;4BACpC,OAAO,EAAE,QAAQ,EAAE,OAAO,IAAI,EAAE;4BAChC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE;4BACzC,IAAI,EAAE,QAAQ;4BACd,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;4BAClC,GAAG,EAAE,GAAG,CAAC,GAAG;yBACb,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,CAAC;YAED,OAAO,QAAQ,CAAC,OAAO,EAAE,CAAC;QAC5B,CAAC;gBAAS,CAAC;YACT,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IAED,mCAAmC;IAEnC,KAAK,CAAC,YAAY,CAAC,SAAiB,EAAE,OAAgB;QACpD,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAE1C,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YAElD,IAAI,CAAC;gBACH,kCAAkC;gBAClC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;gBACzF,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;gBAEhD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACzB,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC;gBAClC,CAAC;gBAED,IAAI,KAAK,EAAE,MAAM,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;oBAChE,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;oBAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;oBAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;oBAC9C,MAAM,QAAQ,GAAG,QAAQ,GAAG,GAAG,GAAG,QAAQ,CAAC;oBAE3C,mDAAmD;oBACnD,MAAM,KAAK,GAAG,OAAO;wBACnB,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC;wBAC1B,CAAC,CAAC,gBAAgB,CAAC;oBAErB,MAAM,KAAK,GAAa,EAAE,CAAC;oBAC3B,IAAI,KAAK,CAAC;oBACV,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;wBAC/C,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;oBACnC,CAAC;oBAED,kDAAkD;oBAClD,MAAM,cAAc,GAAG;wBACrB,wDAAwD;wBACxD,mCAAmC;wBACnC,6CAA6C;qBAC9C,CAAC;oBAEF,KAAK,MAAM,EAAE,IAAI,cAAc,EAAE,CAAC;wBAChC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;4BAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;4BACtB,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gCAClC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;4BACnB,CAAC;wBACH,CAAC;oBACH,CAAC;oBAED,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;gBACnD,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,CAAC;YAED,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC;QAClC,CAAC;gBAAS,CAAC;YACT,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IAED,uBAAuB;IAEvB,KAAK,CAAC,YAAY,CAChB,SAAiB,EACjB,IAAY,EACZ,IAAa;QAEb,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAE3E,kDAAkD;QAClD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC1C,IAAI,YAAY,GAAG,EAAE,CAAC;QACtB,IAAI,eAAe,GAAG,EAAE,CAAC;QACzB,IAAI,UAAU,GAAG,EAAE,CAAC;QAEpB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YAClD,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;gBACzF,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACvB,IAAI,KAAK,EAAE,MAAM,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;wBACjF,YAAY,GAAG,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC;wBACtD,eAAe,GAAG,GAAG,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC;wBAC9C,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;wBACjD,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;wBAC1D,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACpD,CAAC;gBACH,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;QACxB,CAAC;QAED,MAAM,YAAY,GAAG,eAAe,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,eAAe,EAAE,CAAC;QAEpG,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;YAC3C,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;YAC3B,EAAE,EAAE,YAAY;YAChB,OAAO,EAAE,YAAY;YACrB,IAAI,EAAE,IAAI;YACV,IAAI;YACJ,SAAS,EAAE,SAAS;YACpB,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS;SAClE,CAAC,CAAC;QAEH,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;IACvC,CAAC;IAED,6BAA6B;IAErB,KAAK,CAAC,aAAa;QACzB,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI;YACrC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;YAC3B,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;YAC3B,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ;SACpC,CAAC;QAEF,MAAM,MAAM,GAAG,IAAI,mBAAQ,CAAC;YAC1B,IAAI,EAAE,UAAU,CAAC,IAAI;YACrB,IAAI,EAAE,UAAU,CAAC,IAAI,IAAI,GAAG;YAC5B,MAAM,EAAE,UAAU,CAAC,MAAM,KAAK,KAAK;YACnC,IAAI,EAAE;gBACJ,IAAI,EAAE,UAAU,CAAC,IAAI;gBACrB,IAAI,EAAE,UAAU,CAAC,QAAQ;aAC1B;YACD,MAAM,EAAE,KAAY;SACrB,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,+BAA+B;IAEvB,gBAAgB,CAAC,SAAiB;QACxC,6DAA6D;QAC7D,MAAM,aAAa,GAAG,SAAS,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAElE,IAAI,aAAa,EAAE,CAAC;YAClB,oBAAoB;YACpB,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;YAClC,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;YAE/C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,IAAI,CAAC,KAAK,CAAC,8BAA8B,CAAC,EAAE,CAAC;oBAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;oBAC3C,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;wBACnB,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;wBAC5C,0BAA0B;wBAC1B,IAAI,IAAI,CAAC,KAAK,CAAC,gDAAgD,CAAC,EAAE,CAAC;4BACjE,IAAI,GAAG,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;wBAC1C,CAAC;wBACD,gBAAgB;wBAChB,IAAI,IAAI,CAAC,KAAK,CAAC,sCAAsC,CAAC,EAAE,CAAC;4BACvD,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;wBAC1E,CAAC;wBACD,OAAO,IAAI,CAAC;oBACd,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,4CAA4C;QAC5C,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAChD,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACnB,OAAO,SAAS,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/C,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAEO,eAAe,CAAC,SAAiB;QACvC,MAAM,aAAa,GAAG,SAAS,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAElE,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;YAClC,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;YAE/C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,IAAI,CAAC,KAAK,CAAC,6BAA6B,CAAC,EAAE,CAAC;oBAC9C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;oBAC3C,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;wBACnB,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;wBAC5C,IAAI,IAAI,CAAC,KAAK,CAAC,gDAAgD,CAAC,EAAE,CAAC;4BACjE,IAAI,GAAG,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;wBAC1C,CAAC;wBACD,IAAI,IAAI,CAAC,KAAK,CAAC,sCAAsC,CAAC,EAAE,CAAC;4BACvD,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;wBAC1E,CAAC;wBACD,sCAAsC;wBACtC,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;oBACnE,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;IAEO,qBAAqB,CAAC,KAAa;QACzC,OAAO,KAAK;aACT,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,mBAAmB;aAC1C,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACvF,CAAC;IAEO,cAAc;QACpB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IACrE,CAAC;CACF;AA3YD,oCA2YC"}
|
|
1
|
+
{"version":3,"file":"EmailService.js","sourceRoot":"","sources":["../src/EmailService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview A transport for Resend's HTTPS API: one `POST /emails` a message, the API key as the bearer, an
|
|
3
|
+
* `Idempotency-Key` when the caller gives one, the text and the HTML part in one call, and Resend's own retry terms
|
|
4
|
+
* inside one deadline. A refusal keeps the status and Resend's error name, never its message, which can quote an
|
|
5
|
+
* address.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* An attachment path Resend fetches the file from itself: an `http:` or `https:` address. The agent surfaces'
|
|
9
|
+
* attachment check passes an address by this same test, so an address it passes is never read here.
|
|
10
|
+
*/
|
|
11
|
+
export declare const REMOTE_ADDRESS: RegExp;
|
|
12
|
+
/** What the transport needs: the key, and where and as what it calls. */
|
|
13
|
+
export interface ResendOptions {
|
|
14
|
+
/**
|
|
15
|
+
* The API key, or a function that answers it at each send (a key file read when a message goes out). Whitespace around
|
|
16
|
+
* it, such as a key file's final line break, is trimmed.
|
|
17
|
+
*/
|
|
18
|
+
apiKey: string | (() => string);
|
|
19
|
+
/** The API's origin with no trailing slash; Resend's own when unset. */
|
|
20
|
+
baseUrl?: string;
|
|
21
|
+
/** The `User-Agent` every request carries, which Resend requires; the pack's name when unset. */
|
|
22
|
+
userAgent?: string;
|
|
23
|
+
/** The longest one send may take, its retries and their waits included; fifteen seconds when unset. */
|
|
24
|
+
timeoutMs?: number;
|
|
25
|
+
/** The most retries one send makes; two when unset. */
|
|
26
|
+
maxRetries?: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* One file sent with a message: its `content` (Base64 on the wire), or a `path`. An `http:` or `https:` path is the
|
|
30
|
+
* address Resend fetches the file from; a `data:` address or a file on this host is read here and sent as content, as
|
|
31
|
+
* nodemailer reads both over SMTP. With `content` given, a path Resend cannot fetch is left out. This process reads a
|
|
32
|
+
* file path, so it must come from the developer's code and never from a model's output: the pack's `emailSend` tool
|
|
33
|
+
* and channel adapter accept only `content`, `data:` addresses and, through Resend, `http(s)` addresses.
|
|
34
|
+
*/
|
|
35
|
+
export interface OutgoingAttachment {
|
|
36
|
+
filename: string;
|
|
37
|
+
content?: string | Buffer;
|
|
38
|
+
path?: string;
|
|
39
|
+
contentType?: string;
|
|
40
|
+
}
|
|
41
|
+
/** One message as the transport sends it. */
|
|
42
|
+
export interface OutgoingEmail {
|
|
43
|
+
/** The From header; a display name is allowed, as in "Example <hello@example.com>". */
|
|
44
|
+
from: string;
|
|
45
|
+
/** The one recipient. */
|
|
46
|
+
to: string;
|
|
47
|
+
subject: string;
|
|
48
|
+
/** The plain-text part. */
|
|
49
|
+
text: string;
|
|
50
|
+
/** The HTML part, sent in the same call. */
|
|
51
|
+
html?: string;
|
|
52
|
+
replyTo?: string;
|
|
53
|
+
cc?: string;
|
|
54
|
+
bcc?: string;
|
|
55
|
+
/** Headers added to the message, such as `In-Reply-To` and `References` for a reply. */
|
|
56
|
+
headers?: Record<string, string>;
|
|
57
|
+
/**
|
|
58
|
+
* Resend's `Idempotency-Key`: a second request under the same key within 24 hours delivers nothing more. At most 256
|
|
59
|
+
* characters, and never personal data.
|
|
60
|
+
*/
|
|
61
|
+
idempotencyKey?: string;
|
|
62
|
+
attachments?: OutgoingAttachment[];
|
|
63
|
+
}
|
|
64
|
+
/** A send Resend answered outside 2xx: its status, Resend's error name (`unknown` when it named none) and the wait it asked for. */
|
|
65
|
+
export declare class EmailApiError extends Error {
|
|
66
|
+
/** The type's own name. */
|
|
67
|
+
name: string;
|
|
68
|
+
/** The HTTP status Resend answered with. */
|
|
69
|
+
readonly status: number;
|
|
70
|
+
/** Resend's error name, such as `rate_limit_exceeded`, or `unknown`. */
|
|
71
|
+
readonly type: string;
|
|
72
|
+
/** The seconds the answer's `retry-after` header asked for, or null. */
|
|
73
|
+
readonly retryAfterSeconds: number | null;
|
|
74
|
+
constructor(status: number, type: string, retryAfterSeconds: number | null);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The wait before the next try, in seconds, or null when the refusal is not tried again: a rate limit always (it was
|
|
78
|
+
* refused before anything was sent), and under an idempotency key a 409 `concurrent_idempotent_requests` and any 5xx,
|
|
79
|
+
* which Resend's errors page answers with "Try the request again later"; never a quota, a validation error or
|
|
80
|
+
* `invalid_idempotent_request`. The wait is the answer's `retry-after`, else one second, then two.
|
|
81
|
+
*/
|
|
82
|
+
export declare function retryWaitSeconds(error: EmailApiError, keyed: boolean, retry: number): number | null;
|
|
83
|
+
/** Resend's send call. */
|
|
84
|
+
export declare class ResendTransport {
|
|
85
|
+
private readonly options;
|
|
86
|
+
constructor(options: ResendOptions);
|
|
87
|
+
/**
|
|
88
|
+
* Sends one message: the key read once and trimmed, then `POST /emails`, tried again on Resend's terms while the
|
|
89
|
+
* deadline allows. Throws an `Error` before any request when the key, the idempotency key or the User-Agent holds a
|
|
90
|
+
* character an HTTP header cannot carry, with a message that names the field and none of its value; `EmailApiError`
|
|
91
|
+
* for a refusal; and what `fetch` throws for a connection that fails (`TypeError`) or the deadline (`TimeoutError`),
|
|
92
|
+
* so a caller can tell them apart. A 2xx answer always resolves, since Resend has taken the email: its `messageId` is
|
|
93
|
+
* the empty string when the answer names no id or its body cannot be read before the deadline. An attachment from a
|
|
94
|
+
* `data:` address or a file on this host is read first, before the deadline starts; a file that cannot be read throws
|
|
95
|
+
* its own error before any request.
|
|
96
|
+
*/
|
|
97
|
+
send(message: OutgoingEmail): Promise<{
|
|
98
|
+
messageId: string;
|
|
99
|
+
}>;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=ResendTransport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResendTransport.d.ts","sourceRoot":"","sources":["../src/ResendTransport.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2BH;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAkB,CAAC;AAK9C,yEAAyE;AACzE,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IAChC,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iGAAiG;IACjG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uGAAuG;IACvG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,6CAA6C;AAC7C,MAAM,WAAW,aAAa;IAC5B,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wFAAwF;IACxF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,kBAAkB,EAAE,CAAC;CACpC;AAED,oIAAoI;AACpI,qBAAa,aAAc,SAAQ,KAAK;IACtC,2BAA2B;IAClB,IAAI,SAAmB;IAEhC,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,wEAAwE;IACxE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;gBAE9B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,IAAI;CAM3E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGnG;AAsFD,0BAA0B;AAC1B,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;gBAE5B,OAAO,EAAE,aAAa;IAIlC;;;;;;;;;OASG;IACG,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CAwBnE"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview A transport for Resend's HTTPS API: one `POST /emails` a message, the API key as the bearer, an
|
|
4
|
+
* `Idempotency-Key` when the caller gives one, the text and the HTML part in one call, and Resend's own retry terms
|
|
5
|
+
* inside one deadline. A refusal keeps the status and Resend's error name, never its message, which can quote an
|
|
6
|
+
* address.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.ResendTransport = exports.EmailApiError = exports.REMOTE_ADDRESS = void 0;
|
|
10
|
+
exports.retryWaitSeconds = retryWaitSeconds;
|
|
11
|
+
const promises_1 = require("node:fs/promises");
|
|
12
|
+
/** Resend's API origin. */
|
|
13
|
+
const RESEND_API = 'https://api.resend.com';
|
|
14
|
+
/** The `User-Agent` sent when the caller names none: Resend refuses a request without one. */
|
|
15
|
+
const DEFAULT_USER_AGENT = 'agentos-ext-channel-email';
|
|
16
|
+
/** The longest one send may take when the caller names no deadline, retries and their waits included. */
|
|
17
|
+
const DEFAULT_TIMEOUT_MS = 15000;
|
|
18
|
+
/** The retries one send makes at most when the caller names no number. */
|
|
19
|
+
const DEFAULT_MAX_RETRIES = 2;
|
|
20
|
+
/** The shape of an error name Resend gives, such as `validation_error`; any other value is read as `unknown`. */
|
|
21
|
+
const ERROR_NAME = /^[A-Za-z0-9_.:-]{1,64}$/;
|
|
22
|
+
/**
|
|
23
|
+
* A character an HTTP header value cannot carry through Node's `fetch` (undici), whose own header check this is: only a
|
|
24
|
+
* tab, a space, the visible ASCII characters and U+0080 to U+00FF pass. `Headers` throws a `TypeError` for a character
|
|
25
|
+
* above U+00FF and for a NUL, CR or LF inside the value (that one quoting the whole value, key and all), and the
|
|
26
|
+
* request fails for any other control character.
|
|
27
|
+
*/
|
|
28
|
+
const NOT_A_HEADER_CHARACTER = /[^\t\x20-\x7e\x80-\xff]/;
|
|
29
|
+
/**
|
|
30
|
+
* An attachment path Resend fetches the file from itself: an `http:` or `https:` address. The agent surfaces'
|
|
31
|
+
* attachment check passes an address by this same test, so an address it passes is never read here.
|
|
32
|
+
*/
|
|
33
|
+
exports.REMOTE_ADDRESS = /^https?:\/\//i;
|
|
34
|
+
/** A `data:` address, which holds its attachment's bytes in itself. */
|
|
35
|
+
const DATA_ADDRESS = /^data:/i;
|
|
36
|
+
/** A send Resend answered outside 2xx: its status, Resend's error name (`unknown` when it named none) and the wait it asked for. */
|
|
37
|
+
class EmailApiError extends Error {
|
|
38
|
+
constructor(status, type, retryAfterSeconds) {
|
|
39
|
+
super(`Resend refused the email with ${status} ${type}`);
|
|
40
|
+
/** The type's own name. */
|
|
41
|
+
this.name = 'EmailApiError';
|
|
42
|
+
this.status = status;
|
|
43
|
+
this.type = type;
|
|
44
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.EmailApiError = EmailApiError;
|
|
48
|
+
/**
|
|
49
|
+
* The wait before the next try, in seconds, or null when the refusal is not tried again: a rate limit always (it was
|
|
50
|
+
* refused before anything was sent), and under an idempotency key a 409 `concurrent_idempotent_requests` and any 5xx,
|
|
51
|
+
* which Resend's errors page answers with "Try the request again later"; never a quota, a validation error or
|
|
52
|
+
* `invalid_idempotent_request`. The wait is the answer's `retry-after`, else one second, then two.
|
|
53
|
+
*/
|
|
54
|
+
function retryWaitSeconds(error, keyed, retry) {
|
|
55
|
+
const tryAgain = error.type === 'rate_limit_exceeded' || (keyed && (error.type === 'concurrent_idempotent_requests' || error.status >= 500));
|
|
56
|
+
return tryAgain ? (error.retryAfterSeconds ?? retry) : null;
|
|
57
|
+
}
|
|
58
|
+
/** The answer's `retry-after` in seconds, or null when it is absent or not a number of seconds. */
|
|
59
|
+
function retryAfterOf(headers) {
|
|
60
|
+
const raw = headers.get('retry-after');
|
|
61
|
+
if (raw === null || raw.trim() === '')
|
|
62
|
+
return null;
|
|
63
|
+
const seconds = Number(raw);
|
|
64
|
+
return Number.isFinite(seconds) && seconds >= 0 ? seconds : null;
|
|
65
|
+
}
|
|
66
|
+
/** A refusal read from Resend's answer: the status, the error's name when it is a word, the wait; the rest dropped. */
|
|
67
|
+
async function refusalOf(answer) {
|
|
68
|
+
let type = 'unknown';
|
|
69
|
+
try {
|
|
70
|
+
const body = await answer.json();
|
|
71
|
+
const name = typeof body === 'object' && body !== null && 'name' in body ? body.name : undefined;
|
|
72
|
+
if (typeof name === 'string' && ERROR_NAME.test(name))
|
|
73
|
+
type = name;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// not JSON: the name stays unknown
|
|
77
|
+
}
|
|
78
|
+
return new EmailApiError(answer.status, type, retryAfterOf(answer.headers));
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The message's id from a 2xx answer, or the empty string when the answer's body names none or cannot be read (not
|
|
82
|
+
* JSON, no `id`, or cut off by the deadline). A 2xx means Resend took the email, so the send still succeeds: a failure
|
|
83
|
+
* reported here would lead a caller to send the email a second time.
|
|
84
|
+
*/
|
|
85
|
+
async function messageIdOf(answer) {
|
|
86
|
+
try {
|
|
87
|
+
const body = await answer.json();
|
|
88
|
+
const id = typeof body === 'object' && body !== null && 'id' in body ? body.id : undefined;
|
|
89
|
+
return typeof id === 'string' ? id : '';
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return '';
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** What a path Resend cannot fetch holds: a `data:` address decoded, with its media type, or a file on this host read. */
|
|
96
|
+
async function readAttachment(path) {
|
|
97
|
+
if (DATA_ADDRESS.test(path)) {
|
|
98
|
+
// fetch decodes a data: address itself, Base64 or percent-encoded, by the Fetch standard's data: URL processor.
|
|
99
|
+
const decoded = await fetch(path);
|
|
100
|
+
return { bytes: Buffer.from(await decoded.arrayBuffer()), type: decoded.headers.get('content-type') };
|
|
101
|
+
}
|
|
102
|
+
return { bytes: await (0, promises_1.readFile)(path), type: null };
|
|
103
|
+
}
|
|
104
|
+
/** One attachment in Resend's shape: an `http:` or `https:` path as Resend's own, any other path read into content. */
|
|
105
|
+
async function attachmentOf(attachment) {
|
|
106
|
+
const shaped = { filename: attachment.filename };
|
|
107
|
+
if (attachment.content !== undefined) {
|
|
108
|
+
shaped.content = (typeof attachment.content === 'string' ? Buffer.from(attachment.content) : attachment.content).toString('base64');
|
|
109
|
+
}
|
|
110
|
+
if (attachment.path !== undefined && exports.REMOTE_ADDRESS.test(attachment.path)) {
|
|
111
|
+
shaped.path = attachment.path;
|
|
112
|
+
}
|
|
113
|
+
else if (attachment.path !== undefined && attachment.content === undefined) {
|
|
114
|
+
const { bytes, type } = await readAttachment(attachment.path);
|
|
115
|
+
shaped.content = bytes.toString('base64');
|
|
116
|
+
if (type !== null)
|
|
117
|
+
shaped.content_type = type;
|
|
118
|
+
}
|
|
119
|
+
if (attachment.contentType !== undefined)
|
|
120
|
+
shaped.content_type = attachment.contentType;
|
|
121
|
+
return shaped;
|
|
122
|
+
}
|
|
123
|
+
/** The request's JSON body: the fields Resend's send call names, and only those the message carries. */
|
|
124
|
+
async function bodyOf(message) {
|
|
125
|
+
const body = { from: message.from, to: [message.to], subject: message.subject, text: message.text };
|
|
126
|
+
if (message.html !== undefined)
|
|
127
|
+
body.html = message.html;
|
|
128
|
+
if (message.replyTo !== undefined)
|
|
129
|
+
body.reply_to = message.replyTo;
|
|
130
|
+
if (message.cc !== undefined)
|
|
131
|
+
body.cc = message.cc;
|
|
132
|
+
if (message.bcc !== undefined)
|
|
133
|
+
body.bcc = message.bcc;
|
|
134
|
+
if (message.headers !== undefined)
|
|
135
|
+
body.headers = message.headers;
|
|
136
|
+
if (message.attachments !== undefined && message.attachments.length > 0)
|
|
137
|
+
body.attachments = await Promise.all(message.attachments.map(attachmentOf));
|
|
138
|
+
return body;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Throws an `Error` that names the field and none of its value when a header's value holds a character a header cannot
|
|
142
|
+
* carry, so the send stops before any request rather than inside `fetch` with a `TypeError` that reads as a failed
|
|
143
|
+
* connection.
|
|
144
|
+
*/
|
|
145
|
+
function requireHeaderValue(value, field) {
|
|
146
|
+
if (NOT_A_HEADER_CHARACTER.test(value))
|
|
147
|
+
throw new Error(`${field} holds a character an HTTP header cannot carry`);
|
|
148
|
+
}
|
|
149
|
+
/** Resend's send call. */
|
|
150
|
+
class ResendTransport {
|
|
151
|
+
constructor(options) {
|
|
152
|
+
this.options = options;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Sends one message: the key read once and trimmed, then `POST /emails`, tried again on Resend's terms while the
|
|
156
|
+
* deadline allows. Throws an `Error` before any request when the key, the idempotency key or the User-Agent holds a
|
|
157
|
+
* character an HTTP header cannot carry, with a message that names the field and none of its value; `EmailApiError`
|
|
158
|
+
* for a refusal; and what `fetch` throws for a connection that fails (`TypeError`) or the deadline (`TimeoutError`),
|
|
159
|
+
* so a caller can tell them apart. A 2xx answer always resolves, since Resend has taken the email: its `messageId` is
|
|
160
|
+
* the empty string when the answer names no id or its body cannot be read before the deadline. An attachment from a
|
|
161
|
+
* `data:` address or a file on this host is read first, before the deadline starts; a file that cannot be read throws
|
|
162
|
+
* its own error before any request.
|
|
163
|
+
*/
|
|
164
|
+
async send(message) {
|
|
165
|
+
// String() keeps the coercion a template literal gave a key answered outside TypeScript, such as a Buffer.
|
|
166
|
+
const key = String(typeof this.options.apiKey === 'function' ? this.options.apiKey() : this.options.apiKey).trim();
|
|
167
|
+
requireHeaderValue(key, 'The Resend API key');
|
|
168
|
+
const userAgent = this.options.userAgent ?? DEFAULT_USER_AGENT;
|
|
169
|
+
requireHeaderValue(userAgent, 'The User-Agent');
|
|
170
|
+
if (message.idempotencyKey !== undefined)
|
|
171
|
+
requireHeaderValue(message.idempotencyKey, 'The idempotency key');
|
|
172
|
+
const body = JSON.stringify(await bodyOf(message));
|
|
173
|
+
const timeoutMs = this.options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
174
|
+
const maxRetries = this.options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
175
|
+
const deadline = Date.now() + timeoutMs;
|
|
176
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
177
|
+
const headers = new Headers({ Authorization: `Bearer ${key}`, 'Content-Type': 'application/json', 'User-Agent': userAgent });
|
|
178
|
+
if (message.idempotencyKey !== undefined)
|
|
179
|
+
headers.set('Idempotency-Key', message.idempotencyKey);
|
|
180
|
+
const url = `${(this.options.baseUrl ?? RESEND_API).replace(/\/+$/, '')}/emails`;
|
|
181
|
+
for (let retry = 0;; retry += 1) {
|
|
182
|
+
const answer = await fetch(url, { method: 'POST', headers, body, redirect: 'error', signal });
|
|
183
|
+
if (answer.ok)
|
|
184
|
+
return { messageId: await messageIdOf(answer) };
|
|
185
|
+
const error = await refusalOf(answer);
|
|
186
|
+
const wait = retry < maxRetries ? retryWaitSeconds(error, message.idempotencyKey !== undefined, retry + 1) : null;
|
|
187
|
+
if (wait === null || Date.now() + wait * 1000 >= deadline)
|
|
188
|
+
throw error;
|
|
189
|
+
await new Promise((resolve) => setTimeout(resolve, wait * 1000));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
exports.ResendTransport = ResendTransport;
|
|
194
|
+
//# sourceMappingURL=ResendTransport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResendTransport.js","sourceRoot":"","sources":["../src/ResendTransport.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAuHH,4CAGC;AAxHD,+CAA4C;AAE5C,2BAA2B;AAC3B,MAAM,UAAU,GAAG,wBAAwB,CAAC;AAE5C,8FAA8F;AAC9F,MAAM,kBAAkB,GAAG,2BAA2B,CAAC;AAEvD,yGAAyG;AACzG,MAAM,kBAAkB,GAAG,KAAM,CAAC;AAElC,0EAA0E;AAC1E,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B,iHAAiH;AACjH,MAAM,UAAU,GAAG,yBAAyB,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,sBAAsB,GAAG,yBAAyB,CAAC;AAEzD;;;GAGG;AACU,QAAA,cAAc,GAAG,eAAe,CAAC;AAE9C,uEAAuE;AACvE,MAAM,YAAY,GAAG,SAAS,CAAC;AAyD/B,oIAAoI;AACpI,MAAa,aAAc,SAAQ,KAAK;IAatC,YAAY,MAAc,EAAE,IAAY,EAAE,iBAAgC;QACxE,KAAK,CAAC,iCAAiC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;QAb3D,2BAA2B;QAClB,SAAI,GAAG,eAAe,CAAC;QAa9B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;IAC7C,CAAC;CACF;AAnBD,sCAmBC;AAED;;;;;GAKG;AACH,SAAgB,gBAAgB,CAAC,KAAoB,EAAE,KAAc,EAAE,KAAa;IAClF,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,KAAK,qBAAqB,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,gCAAgC,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC;IAC7I,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,iBAAiB,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9D,CAAC;AAED,mGAAmG;AACnG,SAAS,YAAY,CAAC,OAAgB;IACpC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACvC,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5B,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACnE,CAAC;AAED,uHAAuH;AACvH,KAAK,UAAU,SAAS,CAAC,MAAgB;IACvC,IAAI,IAAI,GAAG,SAAS,CAAC;IACrB,IAAI,CAAC;QACH,MAAM,IAAI,GAAY,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,MAAM,IAAI,IAAI,CAAC,CAAC,CAAE,IAA0B,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACxH,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,IAAI,GAAG,IAAI,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,mCAAmC;IACrC,CAAC;IACD,OAAO,IAAI,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,WAAW,CAAC,MAAgB;IACzC,IAAI,CAAC;QACH,MAAM,IAAI,GAAY,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QAC1C,MAAM,EAAE,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,CAAE,IAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAChH,OAAO,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,0HAA0H;AAC1H,KAAK,UAAU,cAAc,CAAC,IAAY;IACxC,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,gHAAgH;QAChH,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;IACxG,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,MAAM,IAAA,mBAAQ,EAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACrD,CAAC;AAED,uHAAuH;AACvH,KAAK,UAAU,YAAY,CAAC,UAA8B;IACxD,MAAM,MAAM,GAA2B,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC;IACzE,IAAI,UAAU,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACrC,MAAM,CAAC,OAAO,GAAG,CAAC,OAAO,UAAU,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACtI,CAAC;IACD,IAAI,UAAU,CAAC,IAAI,KAAK,SAAS,IAAI,sBAAc,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1E,MAAM,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC;IAChC,CAAC;SAAM,IAAI,UAAU,CAAC,IAAI,KAAK,SAAS,IAAI,UAAU,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC7E,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC9D,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,IAAI,KAAK,IAAI;YAAE,MAAM,CAAC,YAAY,GAAG,IAAI,CAAC;IAChD,CAAC;IACD,IAAI,UAAU,CAAC,WAAW,KAAK,SAAS;QAAE,MAAM,CAAC,YAAY,GAAG,UAAU,CAAC,WAAW,CAAC;IACvF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,wGAAwG;AACxG,KAAK,UAAU,MAAM,CAAC,OAAsB;IAC1C,MAAM,IAAI,GAA4B,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;IAC7H,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;QAAE,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IACzD,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;QAAE,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IACnE,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS;QAAE,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;IACnD,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS;QAAE,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACtD,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;QAAE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAClE,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,WAAW,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC;IACrJ,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,KAAa,EAAE,KAAa;IACtD,IAAI,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,gDAAgD,CAAC,CAAC;AACpH,CAAC;AAED,0BAA0B;AAC1B,MAAa,eAAe;IAG1B,YAAY,OAAsB;QAChC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,IAAI,CAAC,OAAsB;QAC/B,2GAA2G;QAC3G,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QACnH,kBAAkB,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,kBAAkB,CAAC;QAC/D,kBAAkB,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;QAChD,IAAI,OAAO,CAAC,cAAc,KAAK,SAAS;YAAE,kBAAkB,CAAC,OAAO,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;QAC5G,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,kBAAkB,CAAC;QAC/D,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,mBAAmB,CAAC;QAClE,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACxC,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,EAAE,aAAa,EAAE,UAAU,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC,CAAC;QAC7H,IAAI,OAAO,CAAC,cAAc,KAAK,SAAS;YAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;QACjG,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,UAAU,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC;QACjF,KAAK,IAAI,KAAK,GAAG,CAAC,GAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAC9F,IAAI,MAAM,CAAC,EAAE;gBAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/D,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;YACtC,MAAM,IAAI,GAAG,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,cAAc,KAAK,SAAS,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAClH,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,IAAI,QAAQ;gBAAE,MAAM,KAAK,CAAC;YACvE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;CACF;AAzCD,0CAyCC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The attachment check of the pack's two agent surfaces, the `emailSend` tool and the channel adapter,
|
|
3
|
+
* whose arguments a model writes. `EmailService.sendEmail` reads a file path on this host, and through SMTP fetches an
|
|
4
|
+
* `http:` or `https:` address from this host, so text that steers an agent could have it mail any file the process can
|
|
5
|
+
* read, or the answer of an address only this host reaches. The two surfaces pass on only what neither transport reads
|
|
6
|
+
* or fetches here.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Throws an `Error` when an attachment an agent named would make this process read a file or fetch an address, before
|
|
10
|
+
* anything is sent and without reading the file or fetching the address. An attachment passes when its `content`, if
|
|
11
|
+
* given, is a string or a Buffer, and its `path`, if given, is a `data:` address, or an `http:` or `https:` address
|
|
12
|
+
* while the service sends through Resend, whose servers fetch it. A path is checked even next to `content`, since
|
|
13
|
+
* nodemailer reads `path` first, and `content` of any other kind is refused, since nodemailer reads the `path` or
|
|
14
|
+
* fetches the `href` of a content object. The message names the attachment's `filename`, or its place in the list when
|
|
15
|
+
* it has none, and the rule, never its path.
|
|
16
|
+
*
|
|
17
|
+
* @param attachments The attachments as the surface took them. `undefined` or `null` passes, since there is nothing to
|
|
18
|
+
* send. Any other value that is not a list is refused, since nodemailer takes a single attachment object as a list of
|
|
19
|
+
* one and reads its `path`.
|
|
20
|
+
* @param throughResend Whether the service sends through Resend, as `EmailService.transport` tells.
|
|
21
|
+
*/
|
|
22
|
+
export declare function requireAgentAttachments(attachments: unknown, throughResend: boolean): void;
|
|
23
|
+
//# sourceMappingURL=agentAttachments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentAttachments.d.ts","sourceRoot":"","sources":["../src/agentAttachments.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiBH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,GAAG,IAAI,CAgB1F"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview The attachment check of the pack's two agent surfaces, the `emailSend` tool and the channel adapter,
|
|
4
|
+
* whose arguments a model writes. `EmailService.sendEmail` reads a file path on this host, and through SMTP fetches an
|
|
5
|
+
* `http:` or `https:` address from this host, so text that steers an agent could have it mail any file the process can
|
|
6
|
+
* read, or the answer of an address only this host reaches. The two surfaces pass on only what neither transport reads
|
|
7
|
+
* or fetches here.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.requireAgentAttachments = requireAgentAttachments;
|
|
11
|
+
const ResendTransport_js_1 = require("./ResendTransport.js");
|
|
12
|
+
/**
|
|
13
|
+
* A `data:` address up to the comma that ends its header. nodemailer decodes a path only in this form, with `data:` in
|
|
14
|
+
* lowercase and a comma, and reads any other path that is not an `http(s)` address as a file.
|
|
15
|
+
*/
|
|
16
|
+
const DATA_ADDRESS = /^data:[^,]*,/;
|
|
17
|
+
/** The rule a refusal names when the service sends through Resend. */
|
|
18
|
+
const THROUGH_RESEND = 'an attachment takes its content as a string, a data: address or an http(s) address; files on this machine are not read';
|
|
19
|
+
/** The rule a refusal names when the service sends through SMTP. */
|
|
20
|
+
const THROUGH_SMTP = 'through SMTP an attachment takes its content as a string or a data: address; files on this machine are not read and addresses are not fetched';
|
|
21
|
+
/**
|
|
22
|
+
* Throws an `Error` when an attachment an agent named would make this process read a file or fetch an address, before
|
|
23
|
+
* anything is sent and without reading the file or fetching the address. An attachment passes when its `content`, if
|
|
24
|
+
* given, is a string or a Buffer, and its `path`, if given, is a `data:` address, or an `http:` or `https:` address
|
|
25
|
+
* while the service sends through Resend, whose servers fetch it. A path is checked even next to `content`, since
|
|
26
|
+
* nodemailer reads `path` first, and `content` of any other kind is refused, since nodemailer reads the `path` or
|
|
27
|
+
* fetches the `href` of a content object. The message names the attachment's `filename`, or its place in the list when
|
|
28
|
+
* it has none, and the rule, never its path.
|
|
29
|
+
*
|
|
30
|
+
* @param attachments The attachments as the surface took them. `undefined` or `null` passes, since there is nothing to
|
|
31
|
+
* send. Any other value that is not a list is refused, since nodemailer takes a single attachment object as a list of
|
|
32
|
+
* one and reads its `path`.
|
|
33
|
+
* @param throughResend Whether the service sends through Resend, as `EmailService.transport` tells.
|
|
34
|
+
*/
|
|
35
|
+
function requireAgentAttachments(attachments, throughResend) {
|
|
36
|
+
if (attachments === undefined || attachments === null)
|
|
37
|
+
return;
|
|
38
|
+
if (!Array.isArray(attachments))
|
|
39
|
+
throw new Error('The attachments were refused: give them as a list');
|
|
40
|
+
for (const [index, attachment] of attachments.entries()) {
|
|
41
|
+
const { filename, content, path } = (typeof attachment === 'object' && attachment !== null ? attachment : {});
|
|
42
|
+
const contentPasses = content === undefined || typeof content === 'string' || Buffer.isBuffer(content);
|
|
43
|
+
const pathPasses = path === undefined || (typeof path === 'string' && (DATA_ADDRESS.test(path) || (throughResend && ResendTransport_js_1.REMOTE_ADDRESS.test(path))));
|
|
44
|
+
if (contentPasses && pathPasses)
|
|
45
|
+
continue;
|
|
46
|
+
const named = typeof filename === 'string' && filename !== '' ? JSON.stringify(filename) : `number ${index + 1}`;
|
|
47
|
+
throw new Error(`The attachment ${named} was refused: ${throughResend ? THROUGH_RESEND : THROUGH_SMTP}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=agentAttachments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentAttachments.js","sourceRoot":"","sources":["../src/agentAttachments.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AA+BH,0DAgBC;AA7CD,6DAAsD;AAEtD;;;GAGG;AACH,MAAM,YAAY,GAAG,cAAc,CAAC;AAEpC,sEAAsE;AACtE,MAAM,cAAc,GAAG,wHAAwH,CAAC;AAEhJ,oEAAoE;AACpE,MAAM,YAAY,GAChB,+IAA+I,CAAC;AAElJ;;;;;;;;;;;;;GAaG;AACH,SAAgB,uBAAuB,CAAC,WAAoB,EAAE,aAAsB;IAClF,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,IAAI;QAAE,OAAO;IAC9D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACtG,KAAK,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;QACxD,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAI3G,CAAC;QACF,MAAM,aAAa,GAAG,OAAO,KAAK,SAAS,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACvG,MAAM,UAAU,GACd,IAAI,KAAK,SAAS,IAAI,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,mCAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAChI,IAAI,aAAa,IAAI,UAAU;YAAE,SAAS;QAC1C,MAAM,KAAK,GAAG,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,KAAK,GAAG,CAAC,EAAE,CAAC;QACjH,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,iBAAiB,aAAa,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;IAC3G,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* @fileoverview Email Channel Extension for AgentOS.
|
|
3
3
|
*
|
|
4
4
|
* Provides an IChannelAdapter + 5 tools for sending, reading, searching,
|
|
5
|
-
* extracting codes from, and replying to emails
|
|
5
|
+
* extracting codes from, and replying to emails: it sends through SMTP or
|
|
6
|
+
* Resend's HTTPS API and reads through IMAP.
|
|
6
7
|
*
|
|
7
8
|
* @module @framers/agentos-ext-channel-email
|
|
8
9
|
*/
|
|
@@ -17,6 +18,18 @@ export interface EmailChannelOptions {
|
|
|
17
18
|
imapPassword?: string;
|
|
18
19
|
imapPort?: number;
|
|
19
20
|
imapSecure?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Resend's API key. With no SMTP host, mail is sent through Resend's HTTPS API. Falls back to the secret
|
|
23
|
+
* `email.resendApiKey`, then to `RESEND_API_KEY`.
|
|
24
|
+
*/
|
|
25
|
+
resendApiKey?: string;
|
|
26
|
+
/** Resend's API origin, such as a proxy's; Resend's own when unset. */
|
|
27
|
+
resendBaseUrl?: string;
|
|
28
|
+
/**
|
|
29
|
+
* The From header, a display name allowed (`Example <hello@example.com>`). Falls back to `EMAIL_FROM`, then to the
|
|
30
|
+
* SMTP user; required when sending through Resend.
|
|
31
|
+
*/
|
|
32
|
+
from?: string;
|
|
20
33
|
secrets?: Record<string, string>;
|
|
21
34
|
}
|
|
22
35
|
export interface ExtensionContext {
|
|
@@ -38,6 +51,8 @@ export interface ExtensionPack {
|
|
|
38
51
|
export declare function createExtensionPack(context: ExtensionContext): ExtensionPack;
|
|
39
52
|
export { EmailService } from './EmailService.js';
|
|
40
53
|
export type { EmailConfig, SendEmailOptions, EmailMessage, SearchEmailOptions } from './EmailService.js';
|
|
54
|
+
export { ResendTransport, EmailApiError, retryWaitSeconds } from './ResendTransport.js';
|
|
55
|
+
export type { ResendOptions, OutgoingEmail, OutgoingAttachment } from './ResendTransport.js';
|
|
41
56
|
export { EmailChannelAdapter } from './EmailChannelAdapter.js';
|
|
42
57
|
export { EmailSendTool } from './tools/send.js';
|
|
43
58
|
export { EmailReadTool } from './tools/read.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AAeH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAkFD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACtF,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAMD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,aAAa,CAgC5E;AAMD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACzG,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxF,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
* @fileoverview Email Channel Extension for AgentOS.
|
|
5
5
|
*
|
|
6
6
|
* Provides an IChannelAdapter + 5 tools for sending, reading, searching,
|
|
7
|
-
* extracting codes from, and replying to emails
|
|
7
|
+
* extracting codes from, and replying to emails: it sends through SMTP or
|
|
8
|
+
* Resend's HTTPS API and reads through IMAP.
|
|
8
9
|
*
|
|
9
10
|
* @module @framers/agentos-ext-channel-email
|
|
10
11
|
*/
|
|
11
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.EmailReplyTool = exports.EmailExtractCodesTool = exports.EmailSearchTool = exports.EmailReadTool = exports.EmailSendTool = exports.EmailChannelAdapter = exports.EmailService = void 0;
|
|
13
|
+
exports.EmailReplyTool = exports.EmailExtractCodesTool = exports.EmailSearchTool = exports.EmailReadTool = exports.EmailSendTool = exports.EmailChannelAdapter = exports.retryWaitSeconds = exports.EmailApiError = exports.ResendTransport = exports.EmailService = void 0;
|
|
13
14
|
exports.createExtensionPack = createExtensionPack;
|
|
14
15
|
const EmailService_js_1 = require("./EmailService.js");
|
|
15
16
|
const EmailChannelAdapter_js_1 = require("./EmailChannelAdapter.js");
|
|
@@ -40,6 +41,8 @@ function resolveConfig(opts, secrets) {
|
|
|
40
41
|
process.env.SMTP_PASSWORD ??
|
|
41
42
|
process.env.EMAIL_SMTP_PASSWORD ??
|
|
42
43
|
'';
|
|
44
|
+
const resendApiKey = opts.resendApiKey ?? secrets['email.resendApiKey'] ?? process.env.RESEND_API_KEY;
|
|
45
|
+
const from = opts.from ?? process.env.EMAIL_FROM;
|
|
43
46
|
const imapHost = opts.imapHost ??
|
|
44
47
|
secrets['email.imapHost'] ??
|
|
45
48
|
secrets['email.imap.host'] ??
|
|
@@ -55,15 +58,19 @@ function resolveConfig(opts, secrets) {
|
|
|
55
58
|
secrets['email.imap.password'] ??
|
|
56
59
|
process.env.IMAP_PASSWORD ??
|
|
57
60
|
process.env.EMAIL_IMAP_PASSWORD;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
// SMTP stays the transport whenever a host is given; Resend sends only when a key is given and no SMTP host.
|
|
62
|
+
const config = smtpHost === '' && resendApiKey
|
|
63
|
+
? { resend: { apiKey: resendApiKey, baseUrl: opts.resendBaseUrl }, from }
|
|
64
|
+
: {
|
|
65
|
+
smtp: {
|
|
66
|
+
host: smtpHost,
|
|
67
|
+
user: smtpUser,
|
|
68
|
+
password: smtpPassword,
|
|
69
|
+
port: opts.smtpPort,
|
|
70
|
+
secure: opts.smtpSecure,
|
|
71
|
+
},
|
|
72
|
+
from,
|
|
73
|
+
};
|
|
67
74
|
if (imapHost && imapUser && imapPassword) {
|
|
68
75
|
config.imap = {
|
|
69
76
|
host: imapHost,
|
|
@@ -101,7 +108,7 @@ function createExtensionPack(context) {
|
|
|
101
108
|
{ id: 'emailChannel', kind: 'messaging-channel', priority: 50, payload: adapter },
|
|
102
109
|
],
|
|
103
110
|
onActivate: async () => {
|
|
104
|
-
await adapter.initialize({ platform: 'email', credential: config.smtp
|
|
111
|
+
await adapter.initialize({ platform: 'email', credential: config.smtp?.user ?? config.from ?? '' });
|
|
105
112
|
},
|
|
106
113
|
onDeactivate: async () => {
|
|
107
114
|
await adapter.shutdown();
|
|
@@ -113,6 +120,10 @@ function createExtensionPack(context) {
|
|
|
113
120
|
// ---------------------------------------------------------------------------
|
|
114
121
|
var EmailService_js_2 = require("./EmailService.js");
|
|
115
122
|
Object.defineProperty(exports, "EmailService", { enumerable: true, get: function () { return EmailService_js_2.EmailService; } });
|
|
123
|
+
var ResendTransport_js_1 = require("./ResendTransport.js");
|
|
124
|
+
Object.defineProperty(exports, "ResendTransport", { enumerable: true, get: function () { return ResendTransport_js_1.ResendTransport; } });
|
|
125
|
+
Object.defineProperty(exports, "EmailApiError", { enumerable: true, get: function () { return ResendTransport_js_1.EmailApiError; } });
|
|
126
|
+
Object.defineProperty(exports, "retryWaitSeconds", { enumerable: true, get: function () { return ResendTransport_js_1.retryWaitSeconds; } });
|
|
116
127
|
var EmailChannelAdapter_js_2 = require("./EmailChannelAdapter.js");
|
|
117
128
|
Object.defineProperty(exports, "EmailChannelAdapter", { enumerable: true, get: function () { return EmailChannelAdapter_js_2.EmailChannelAdapter; } });
|
|
118
129
|
var send_js_2 = require("./tools/send.js");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,cAAc;AACd
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/send.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export declare class EmailSendTool {
|
|
|
4
4
|
readonly id = "emailSend";
|
|
5
5
|
readonly name = "emailSend";
|
|
6
6
|
readonly displayName = "Send Email";
|
|
7
|
-
readonly description = "Send an email with text or HTML body and optional attachments via SMTP.";
|
|
7
|
+
readonly description = "Send an email with text or HTML body and optional attachments via SMTP or Resend's HTTPS API.";
|
|
8
8
|
readonly category = "communication";
|
|
9
9
|
readonly version = "0.1.0";
|
|
10
10
|
readonly hasSideEffects = true;
|
|
@@ -39,6 +39,10 @@ export declare class EmailSendTool {
|
|
|
39
39
|
type: string;
|
|
40
40
|
description: string;
|
|
41
41
|
};
|
|
42
|
+
content: {
|
|
43
|
+
type: string;
|
|
44
|
+
description: string;
|
|
45
|
+
};
|
|
42
46
|
};
|
|
43
47
|
};
|
|
44
48
|
description: string;
|
|
@@ -47,6 +51,10 @@ export declare class EmailSendTool {
|
|
|
47
51
|
required: string[];
|
|
48
52
|
};
|
|
49
53
|
constructor(service: EmailService);
|
|
54
|
+
/**
|
|
55
|
+
* Sends the email. An attachment passes only as `content`, a `data:` address or, through Resend, an `http(s)`
|
|
56
|
+
* address: any other is refused before anything is sent, with `{ success: false, error }` naming its filename.
|
|
57
|
+
*/
|
|
50
58
|
execute(args: {
|
|
51
59
|
to: string;
|
|
52
60
|
subject: string;
|
package/dist/tools/send.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../src/tools/send.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../src/tools/send.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,qBAAa,aAAa;IAgCZ,OAAO,CAAC,OAAO;IA/B3B,QAAQ,CAAC,EAAE,eAAe;IAC1B,QAAQ,CAAC,IAAI,eAAe;IAC5B,QAAQ,CAAC,WAAW,gBAAgB;IACpC,QAAQ,CAAC,WAAW,mGAAmG;IACvH,QAAQ,CAAC,QAAQ,mBAAmB;IACpC,QAAQ,CAAC,OAAO,WAAW;IAC3B,QAAQ,CAAC,cAAc,QAAQ;IAE/B,QAAQ,CAAC,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAqBlB;gBAEkB,OAAO,EAAE,YAAY;IAEzC;;;OAGG;IACG,OAAO,CAAC,IAAI,EAAE;QAClB,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,KAAK,CAAC;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KAC5E,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAe9D"}
|
package/dist/tools/send.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EmailSendTool = void 0;
|
|
4
|
+
const agentAttachments_js_1 = require("../agentAttachments.js");
|
|
4
5
|
class EmailSendTool {
|
|
5
6
|
constructor(service) {
|
|
6
7
|
this.service = service;
|
|
7
8
|
this.id = 'emailSend';
|
|
8
9
|
this.name = 'emailSend';
|
|
9
10
|
this.displayName = 'Send Email';
|
|
10
|
-
this.description =
|
|
11
|
+
this.description = "Send an email with text or HTML body and optional attachments via SMTP or Resend's HTTPS API.";
|
|
11
12
|
this.category = 'communication';
|
|
12
13
|
this.version = '0.1.0';
|
|
13
14
|
this.hasSideEffects = true;
|
|
@@ -24,7 +25,8 @@ class EmailSendTool {
|
|
|
24
25
|
type: 'object',
|
|
25
26
|
properties: {
|
|
26
27
|
filename: { type: 'string' },
|
|
27
|
-
path: { type: 'string', description: '
|
|
28
|
+
path: { type: 'string', description: 'A data: address, or an http(s) address when sending through Resend; files on this machine are not read' },
|
|
29
|
+
content: { type: 'string', description: "The file's content as text; give a binary file in path as a Base64 data: address" },
|
|
28
30
|
},
|
|
29
31
|
},
|
|
30
32
|
description: 'Optional file attachments',
|
|
@@ -33,8 +35,13 @@ class EmailSendTool {
|
|
|
33
35
|
required: ['to', 'subject', 'body'],
|
|
34
36
|
};
|
|
35
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Sends the email. An attachment passes only as `content`, a `data:` address or, through Resend, an `http(s)`
|
|
40
|
+
* address: any other is refused before anything is sent, with `{ success: false, error }` naming its filename.
|
|
41
|
+
*/
|
|
36
42
|
async execute(args) {
|
|
37
43
|
try {
|
|
44
|
+
(0, agentAttachments_js_1.requireAgentAttachments)(args.attachments, this.service.transport === 'resend');
|
|
38
45
|
const result = await this.service.sendEmail({
|
|
39
46
|
to: args.to,
|
|
40
47
|
subject: args.subject,
|
package/dist/tools/send.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send.js","sourceRoot":"","sources":["../../src/tools/send.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"send.js","sourceRoot":"","sources":["../../src/tools/send.ts"],"names":[],"mappings":";;;AAEA,gEAAiE;AAEjE,MAAa,aAAa;IAgCxB,YAAoB,OAAqB;QAArB,YAAO,GAAP,OAAO,CAAc;QA/BhC,OAAE,GAAG,WAAW,CAAC;QACjB,SAAI,GAAG,WAAW,CAAC;QACnB,gBAAW,GAAG,YAAY,CAAC;QAC3B,gBAAW,GAAG,+FAA+F,CAAC;QAC9G,aAAQ,GAAG,eAAe,CAAC;QAC3B,YAAO,GAAG,OAAO,CAAC;QAClB,mBAAc,GAAG,IAAI,CAAC;QAEtB,gBAAW,GAAG;YACrB,IAAI,EAAE,QAAiB;YACvB,UAAU,EAAE;gBACV,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yBAAyB,EAAE;gBAC9D,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAE;gBAC9D,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,uBAAuB,EAAE;gBAC9D,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0BAA0B,EAAE;gBACjE,WAAW,EAAE;oBACX,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE;wBACL,IAAI,EAAE,QAAQ;wBACd,UAAU,EAAE;4BACV,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;4BAC5B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,wGAAwG,EAAE;4BAC/I,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,kFAAkF,EAAE;yBAC7H;qBACF;oBACD,WAAW,EAAE,2BAA2B;iBACzC;aACF;YACD,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC;SACpC,CAAC;IAE0C,CAAC;IAE7C;;;OAGG;IACH,KAAK,CAAC,OAAO,CAAC,IAMb;QACC,IAAI,CAAC;YACH,IAAA,6CAAuB,EAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC;YAC/E,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;gBAC1C,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,WAAW,EAAE,IAAI,CAAC,WAAW;aAC9B,CAAC,CAAC;YACH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QACzC,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;QAChD,CAAC;IACH,CAAC;CACF;AA3DD,sCA2DC"}
|
package/manifest.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"$schema": "https://agentos.sh/schemas/extension-manifest-v1.json",
|
|
3
3
|
"id": "com.framers.channels.email",
|
|
4
4
|
"name": "Email Channel Extension",
|
|
5
|
-
"version": "0.
|
|
6
|
-
"description": "Bidirectional email integration
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"description": "Bidirectional email integration: send through SMTP or Resend's HTTPS API, and read, search, extract verification codes and reply through IMAP.",
|
|
7
7
|
"categories": ["channel", "communication"],
|
|
8
8
|
"platforms": ["email"],
|
|
9
9
|
"sdk": "nodemailer",
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
{ "kind": "messaging-channel", "id": "emailChannel", "displayName": "Email Channel Adapter" }
|
|
17
17
|
],
|
|
18
18
|
"requiredSecrets": ["email.smtpHost", "email.smtpUser", "email.smtpPassword"],
|
|
19
|
-
"optionalSecrets": ["email.imap.host", "email.imap.user", "email.imap.password"],
|
|
19
|
+
"optionalSecrets": ["email.imap.host", "email.imap.user", "email.imap.password", "email.resendApiKey"],
|
|
20
20
|
"features": [
|
|
21
|
-
"Send emails with text, HTML, and attachments via SMTP",
|
|
21
|
+
"Send emails with text, HTML, and attachments via SMTP or Resend's HTTPS API",
|
|
22
22
|
"Read inbox and other IMAP folders",
|
|
23
23
|
"Search emails by query, folder, and date range",
|
|
24
24
|
"Extract verification codes and OTPs from email bodies",
|
package/package.json
CHANGED
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@framers/agentos-ext-channel-email",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Email channel adapter for AgentOS
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Email channel adapter for AgentOS: send through SMTP or Resend's HTTPS API, and read, search, extract codes and reply through IMAP.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"license": "Apache-2.0",
|
|
7
8
|
"files": [
|
|
8
9
|
"dist",
|
|
9
10
|
"manifest.json"
|
|
10
11
|
],
|
|
11
12
|
"peerDependencies": {
|
|
12
|
-
"@framers/agentos": "
|
|
13
|
+
"@framers/agentos": ">=0.10.40"
|
|
14
|
+
},
|
|
15
|
+
"peerDependenciesMeta": {
|
|
16
|
+
"@framers/agentos": {
|
|
17
|
+
"optional": true
|
|
18
|
+
}
|
|
13
19
|
},
|
|
14
20
|
"dependencies": {
|
|
15
21
|
"imapflow": "^1.0.0",
|
|
16
|
-
"nodemailer": "^
|
|
22
|
+
"nodemailer": "^10.0.16"
|
|
17
23
|
},
|
|
18
24
|
"devDependencies": {
|
|
19
25
|
"@types/node": "^20.0.0",
|
|
20
|
-
"@types/nodemailer": "^6.4.0",
|
|
21
26
|
"typescript": "^5.0.0",
|
|
22
|
-
"vitest": "^
|
|
23
|
-
"@framers/agentos": "^0.
|
|
27
|
+
"vitest": "^3.2.7",
|
|
28
|
+
"@framers/agentos": "^0.13.19"
|
|
24
29
|
},
|
|
25
30
|
"repository": {
|
|
26
31
|
"type": "git",
|