tosend 1.0.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/LICENSE +21 -0
- package/README.md +196 -0
- package/dist/index.d.mts +154 -0
- package/dist/index.d.ts +154 -0
- package/dist/index.js +227 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +201 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) ToSend
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# ToSend Node.js SDK
|
|
2
|
+
|
|
3
|
+
Official Node.js SDK for the [ToSend](https://tosend.com) email API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install tosend
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { ToSend } from 'tosend';
|
|
15
|
+
|
|
16
|
+
const tosend = new ToSend('tsend_your_api_key');
|
|
17
|
+
|
|
18
|
+
const response = await tosend.send({
|
|
19
|
+
from: { email: 'hello@yourdomain.com', name: 'Your App' },
|
|
20
|
+
to: [{ email: 'user@example.com' }],
|
|
21
|
+
subject: 'Welcome!',
|
|
22
|
+
html: '<h1>Hello!</h1><p>Thanks for signing up.</p>',
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
console.log(response.message_id);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### Send an Email
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
const response = await tosend.send({
|
|
34
|
+
from: { email: 'hello@yourdomain.com', name: 'Your App' },
|
|
35
|
+
to: [
|
|
36
|
+
{ email: 'user@example.com' },
|
|
37
|
+
{ email: 'another@example.com', name: 'John Doe' },
|
|
38
|
+
],
|
|
39
|
+
subject: 'Hello!',
|
|
40
|
+
html: '<h1>Welcome</h1>',
|
|
41
|
+
text: 'Welcome', // optional
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### With CC, BCC, and Reply-To
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
const response = await tosend.send({
|
|
49
|
+
from: { email: 'hello@yourdomain.com' },
|
|
50
|
+
to: [{ email: 'user@example.com' }],
|
|
51
|
+
cc: [{ email: 'cc@example.com' }],
|
|
52
|
+
bcc: [{ email: 'bcc@example.com' }],
|
|
53
|
+
reply_to: { email: 'support@yourdomain.com', name: 'Support' },
|
|
54
|
+
subject: 'Hello',
|
|
55
|
+
html: '<p>Hello World</p>',
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### With Attachments
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import * as fs from 'fs';
|
|
63
|
+
|
|
64
|
+
const response = await tosend.send({
|
|
65
|
+
from: { email: 'hello@yourdomain.com' },
|
|
66
|
+
to: [{ email: 'user@example.com' }],
|
|
67
|
+
subject: 'Your Invoice',
|
|
68
|
+
html: '<p>Please find your invoice attached.</p>',
|
|
69
|
+
attachments: [
|
|
70
|
+
{
|
|
71
|
+
type: 'application/pdf',
|
|
72
|
+
name: 'invoice.pdf',
|
|
73
|
+
content: fs.readFileSync('invoice.pdf').toString('base64'),
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Batch Sending
|
|
80
|
+
|
|
81
|
+
Send multiple emails in a single request:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
const response = await tosend.batch([
|
|
85
|
+
{
|
|
86
|
+
from: { email: 'hello@yourdomain.com' },
|
|
87
|
+
to: [{ email: 'user1@example.com' }],
|
|
88
|
+
subject: 'Hello User 1',
|
|
89
|
+
html: '<p>Welcome!</p>',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
from: { email: 'hello@yourdomain.com' },
|
|
93
|
+
to: [{ email: 'user2@example.com' }],
|
|
94
|
+
subject: 'Hello User 2',
|
|
95
|
+
html: '<p>Welcome!</p>',
|
|
96
|
+
},
|
|
97
|
+
]);
|
|
98
|
+
|
|
99
|
+
response.results.forEach((result) => {
|
|
100
|
+
if (result.status === 'success') {
|
|
101
|
+
console.log('Sent:', result.message_id);
|
|
102
|
+
} else {
|
|
103
|
+
console.log('Failed:', result.message);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Get Account Info
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
const info = await tosend.getAccountInfo();
|
|
112
|
+
|
|
113
|
+
console.log(info.account.title);
|
|
114
|
+
console.log(info.account.emails_usage_this_month);
|
|
115
|
+
console.log(info.account.emails_sent_last_24hrs);
|
|
116
|
+
|
|
117
|
+
info.domains.forEach((domain) => {
|
|
118
|
+
console.log(domain.domain_name, domain.verification_status);
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Configuration
|
|
123
|
+
|
|
124
|
+
### Simple (API key only)
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
const tosend = new ToSend('tsend_your_api_key');
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### With Options
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const tosend = new ToSend({
|
|
134
|
+
apiKey: 'tsend_your_api_key',
|
|
135
|
+
baseUrl: 'https://api.tosend.com', // optional
|
|
136
|
+
timeout: 30000, // optional, in milliseconds
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Error Handling
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
import { ToSend, ToSendError } from 'tosend';
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const response = await tosend.send({
|
|
147
|
+
from: { email: 'hello@yourdomain.com' },
|
|
148
|
+
to: [{ email: 'user@example.com' }],
|
|
149
|
+
subject: 'Hello',
|
|
150
|
+
html: '<p>Hello</p>',
|
|
151
|
+
});
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (error instanceof ToSendError) {
|
|
154
|
+
console.log('Error:', error.message);
|
|
155
|
+
console.log('Code:', error.code);
|
|
156
|
+
console.log('Errors:', error.errors);
|
|
157
|
+
|
|
158
|
+
if (error.isValidationError) {
|
|
159
|
+
// Handle validation error (422)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (error.isAuthenticationError) {
|
|
163
|
+
// Handle auth error (401/403)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (error.isRateLimitError) {
|
|
167
|
+
// Handle rate limit (429)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## TypeScript
|
|
174
|
+
|
|
175
|
+
Full TypeScript support with exported types:
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
import {
|
|
179
|
+
ToSend,
|
|
180
|
+
ToSendError,
|
|
181
|
+
SendEmailParams,
|
|
182
|
+
SendEmailResponse,
|
|
183
|
+
BatchEmailResponse,
|
|
184
|
+
AccountInfo,
|
|
185
|
+
Address,
|
|
186
|
+
Attachment,
|
|
187
|
+
} from 'tosend';
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Requirements
|
|
191
|
+
|
|
192
|
+
- Node.js 18 or higher
|
|
193
|
+
|
|
194
|
+
## License
|
|
195
|
+
|
|
196
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToSend Node.js SDK
|
|
3
|
+
*
|
|
4
|
+
* Official SDK for the ToSend email API.
|
|
5
|
+
* @see https://tosend.com/docs
|
|
6
|
+
*/
|
|
7
|
+
interface Address {
|
|
8
|
+
email: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
}
|
|
11
|
+
interface Attachment {
|
|
12
|
+
/** MIME type (e.g., 'application/pdf') */
|
|
13
|
+
type: string;
|
|
14
|
+
/** Filename */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Base64 encoded content */
|
|
17
|
+
content: string;
|
|
18
|
+
}
|
|
19
|
+
interface SendEmailParams {
|
|
20
|
+
/** Sender address */
|
|
21
|
+
from: Address;
|
|
22
|
+
/** Recipients (max 50) */
|
|
23
|
+
to: Address[];
|
|
24
|
+
/** Email subject */
|
|
25
|
+
subject: string;
|
|
26
|
+
/** HTML content */
|
|
27
|
+
html?: string;
|
|
28
|
+
/** Plain text content */
|
|
29
|
+
text?: string;
|
|
30
|
+
/** CC recipients */
|
|
31
|
+
cc?: Address[];
|
|
32
|
+
/** BCC recipients */
|
|
33
|
+
bcc?: Address[];
|
|
34
|
+
/** Reply-to address */
|
|
35
|
+
reply_to?: Address;
|
|
36
|
+
/** Custom headers */
|
|
37
|
+
headers?: Record<string, string>;
|
|
38
|
+
/** File attachments */
|
|
39
|
+
attachments?: Attachment[];
|
|
40
|
+
}
|
|
41
|
+
interface SendEmailResponse {
|
|
42
|
+
message_id: string;
|
|
43
|
+
}
|
|
44
|
+
interface BatchEmailResult {
|
|
45
|
+
status: 'success' | 'error' | 'spam';
|
|
46
|
+
message_id?: string;
|
|
47
|
+
message?: string;
|
|
48
|
+
errors?: Record<string, Record<string, string>>;
|
|
49
|
+
}
|
|
50
|
+
interface BatchEmailResponse {
|
|
51
|
+
results: BatchEmailResult[];
|
|
52
|
+
}
|
|
53
|
+
interface Domain {
|
|
54
|
+
domain_name: string;
|
|
55
|
+
verification_status: 'pending' | 'verified' | 'failed';
|
|
56
|
+
created_at: string;
|
|
57
|
+
}
|
|
58
|
+
interface AccountInfo {
|
|
59
|
+
account: {
|
|
60
|
+
title: string;
|
|
61
|
+
plan_type: string;
|
|
62
|
+
status: string;
|
|
63
|
+
emails_usage_this_month: number;
|
|
64
|
+
emails_sent_last_24hrs: number;
|
|
65
|
+
};
|
|
66
|
+
domains: Domain[];
|
|
67
|
+
}
|
|
68
|
+
interface ToSendErrorResponse {
|
|
69
|
+
error_code: number;
|
|
70
|
+
message: string;
|
|
71
|
+
errors?: Record<string, Record<string, string>>;
|
|
72
|
+
}
|
|
73
|
+
interface ToSendConfig {
|
|
74
|
+
/** Your ToSend API key */
|
|
75
|
+
apiKey: string;
|
|
76
|
+
/** Custom base URL (optional) */
|
|
77
|
+
baseUrl?: string;
|
|
78
|
+
/** Request timeout in ms (default: 30000) */
|
|
79
|
+
timeout?: number;
|
|
80
|
+
}
|
|
81
|
+
declare class ToSendError extends Error {
|
|
82
|
+
readonly code: number;
|
|
83
|
+
readonly errors: Record<string, Record<string, string>>;
|
|
84
|
+
constructor(message: string, code?: number, errors?: Record<string, Record<string, string>>);
|
|
85
|
+
get isValidationError(): boolean;
|
|
86
|
+
get isAuthenticationError(): boolean;
|
|
87
|
+
get isRateLimitError(): boolean;
|
|
88
|
+
}
|
|
89
|
+
declare class ToSend {
|
|
90
|
+
private readonly apiKey;
|
|
91
|
+
private readonly baseUrl;
|
|
92
|
+
private readonly timeout;
|
|
93
|
+
constructor(config: string | ToSendConfig);
|
|
94
|
+
/**
|
|
95
|
+
* Send a single email.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* const response = await tosend.send({
|
|
100
|
+
* from: { email: 'hello@example.com', name: 'My App' },
|
|
101
|
+
* to: [{ email: 'user@example.com' }],
|
|
102
|
+
* subject: 'Hello!',
|
|
103
|
+
* html: '<p>Welcome!</p>'
|
|
104
|
+
* });
|
|
105
|
+
* console.log(response.message_id);
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
send(params: SendEmailParams): Promise<SendEmailResponse>;
|
|
109
|
+
/**
|
|
110
|
+
* Send multiple emails in a single request.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* const response = await tosend.batch([
|
|
115
|
+
* {
|
|
116
|
+
* from: { email: 'hello@example.com' },
|
|
117
|
+
* to: [{ email: 'user1@example.com' }],
|
|
118
|
+
* subject: 'Hello User 1',
|
|
119
|
+
* html: '<p>Hi!</p>'
|
|
120
|
+
* },
|
|
121
|
+
* {
|
|
122
|
+
* from: { email: 'hello@example.com' },
|
|
123
|
+
* to: [{ email: 'user2@example.com' }],
|
|
124
|
+
* subject: 'Hello User 2',
|
|
125
|
+
* html: '<p>Hi!</p>'
|
|
126
|
+
* }
|
|
127
|
+
* ]);
|
|
128
|
+
*
|
|
129
|
+
* response.results.forEach(result => {
|
|
130
|
+
* if (result.status === 'success') {
|
|
131
|
+
* console.log('Sent:', result.message_id);
|
|
132
|
+
* }
|
|
133
|
+
* });
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
batch(emails: SendEmailParams[]): Promise<BatchEmailResponse>;
|
|
137
|
+
/**
|
|
138
|
+
* Get account information and domains.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* const info = await tosend.getAccountInfo();
|
|
143
|
+
* console.log(info.account.title);
|
|
144
|
+
* console.log(info.account.emails_usage_this_month);
|
|
145
|
+
* info.domains.forEach(d => console.log(d.domain_name, d.verification_status));
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
getAccountInfo(): Promise<AccountInfo>;
|
|
149
|
+
private validateEmailParams;
|
|
150
|
+
private isValidEmail;
|
|
151
|
+
private request;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export { type AccountInfo, type Address, type Attachment, type BatchEmailResponse, type BatchEmailResult, type Domain, type SendEmailParams, type SendEmailResponse, ToSend, type ToSendConfig, ToSendError, type ToSendErrorResponse, ToSend as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToSend Node.js SDK
|
|
3
|
+
*
|
|
4
|
+
* Official SDK for the ToSend email API.
|
|
5
|
+
* @see https://tosend.com/docs
|
|
6
|
+
*/
|
|
7
|
+
interface Address {
|
|
8
|
+
email: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
}
|
|
11
|
+
interface Attachment {
|
|
12
|
+
/** MIME type (e.g., 'application/pdf') */
|
|
13
|
+
type: string;
|
|
14
|
+
/** Filename */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Base64 encoded content */
|
|
17
|
+
content: string;
|
|
18
|
+
}
|
|
19
|
+
interface SendEmailParams {
|
|
20
|
+
/** Sender address */
|
|
21
|
+
from: Address;
|
|
22
|
+
/** Recipients (max 50) */
|
|
23
|
+
to: Address[];
|
|
24
|
+
/** Email subject */
|
|
25
|
+
subject: string;
|
|
26
|
+
/** HTML content */
|
|
27
|
+
html?: string;
|
|
28
|
+
/** Plain text content */
|
|
29
|
+
text?: string;
|
|
30
|
+
/** CC recipients */
|
|
31
|
+
cc?: Address[];
|
|
32
|
+
/** BCC recipients */
|
|
33
|
+
bcc?: Address[];
|
|
34
|
+
/** Reply-to address */
|
|
35
|
+
reply_to?: Address;
|
|
36
|
+
/** Custom headers */
|
|
37
|
+
headers?: Record<string, string>;
|
|
38
|
+
/** File attachments */
|
|
39
|
+
attachments?: Attachment[];
|
|
40
|
+
}
|
|
41
|
+
interface SendEmailResponse {
|
|
42
|
+
message_id: string;
|
|
43
|
+
}
|
|
44
|
+
interface BatchEmailResult {
|
|
45
|
+
status: 'success' | 'error' | 'spam';
|
|
46
|
+
message_id?: string;
|
|
47
|
+
message?: string;
|
|
48
|
+
errors?: Record<string, Record<string, string>>;
|
|
49
|
+
}
|
|
50
|
+
interface BatchEmailResponse {
|
|
51
|
+
results: BatchEmailResult[];
|
|
52
|
+
}
|
|
53
|
+
interface Domain {
|
|
54
|
+
domain_name: string;
|
|
55
|
+
verification_status: 'pending' | 'verified' | 'failed';
|
|
56
|
+
created_at: string;
|
|
57
|
+
}
|
|
58
|
+
interface AccountInfo {
|
|
59
|
+
account: {
|
|
60
|
+
title: string;
|
|
61
|
+
plan_type: string;
|
|
62
|
+
status: string;
|
|
63
|
+
emails_usage_this_month: number;
|
|
64
|
+
emails_sent_last_24hrs: number;
|
|
65
|
+
};
|
|
66
|
+
domains: Domain[];
|
|
67
|
+
}
|
|
68
|
+
interface ToSendErrorResponse {
|
|
69
|
+
error_code: number;
|
|
70
|
+
message: string;
|
|
71
|
+
errors?: Record<string, Record<string, string>>;
|
|
72
|
+
}
|
|
73
|
+
interface ToSendConfig {
|
|
74
|
+
/** Your ToSend API key */
|
|
75
|
+
apiKey: string;
|
|
76
|
+
/** Custom base URL (optional) */
|
|
77
|
+
baseUrl?: string;
|
|
78
|
+
/** Request timeout in ms (default: 30000) */
|
|
79
|
+
timeout?: number;
|
|
80
|
+
}
|
|
81
|
+
declare class ToSendError extends Error {
|
|
82
|
+
readonly code: number;
|
|
83
|
+
readonly errors: Record<string, Record<string, string>>;
|
|
84
|
+
constructor(message: string, code?: number, errors?: Record<string, Record<string, string>>);
|
|
85
|
+
get isValidationError(): boolean;
|
|
86
|
+
get isAuthenticationError(): boolean;
|
|
87
|
+
get isRateLimitError(): boolean;
|
|
88
|
+
}
|
|
89
|
+
declare class ToSend {
|
|
90
|
+
private readonly apiKey;
|
|
91
|
+
private readonly baseUrl;
|
|
92
|
+
private readonly timeout;
|
|
93
|
+
constructor(config: string | ToSendConfig);
|
|
94
|
+
/**
|
|
95
|
+
* Send a single email.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* const response = await tosend.send({
|
|
100
|
+
* from: { email: 'hello@example.com', name: 'My App' },
|
|
101
|
+
* to: [{ email: 'user@example.com' }],
|
|
102
|
+
* subject: 'Hello!',
|
|
103
|
+
* html: '<p>Welcome!</p>'
|
|
104
|
+
* });
|
|
105
|
+
* console.log(response.message_id);
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
send(params: SendEmailParams): Promise<SendEmailResponse>;
|
|
109
|
+
/**
|
|
110
|
+
* Send multiple emails in a single request.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* const response = await tosend.batch([
|
|
115
|
+
* {
|
|
116
|
+
* from: { email: 'hello@example.com' },
|
|
117
|
+
* to: [{ email: 'user1@example.com' }],
|
|
118
|
+
* subject: 'Hello User 1',
|
|
119
|
+
* html: '<p>Hi!</p>'
|
|
120
|
+
* },
|
|
121
|
+
* {
|
|
122
|
+
* from: { email: 'hello@example.com' },
|
|
123
|
+
* to: [{ email: 'user2@example.com' }],
|
|
124
|
+
* subject: 'Hello User 2',
|
|
125
|
+
* html: '<p>Hi!</p>'
|
|
126
|
+
* }
|
|
127
|
+
* ]);
|
|
128
|
+
*
|
|
129
|
+
* response.results.forEach(result => {
|
|
130
|
+
* if (result.status === 'success') {
|
|
131
|
+
* console.log('Sent:', result.message_id);
|
|
132
|
+
* }
|
|
133
|
+
* });
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
batch(emails: SendEmailParams[]): Promise<BatchEmailResponse>;
|
|
137
|
+
/**
|
|
138
|
+
* Get account information and domains.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* const info = await tosend.getAccountInfo();
|
|
143
|
+
* console.log(info.account.title);
|
|
144
|
+
* console.log(info.account.emails_usage_this_month);
|
|
145
|
+
* info.domains.forEach(d => console.log(d.domain_name, d.verification_status));
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
getAccountInfo(): Promise<AccountInfo>;
|
|
149
|
+
private validateEmailParams;
|
|
150
|
+
private isValidEmail;
|
|
151
|
+
private request;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export { type AccountInfo, type Address, type Attachment, type BatchEmailResponse, type BatchEmailResult, type Domain, type SendEmailParams, type SendEmailResponse, ToSend, type ToSendConfig, ToSendError, type ToSendErrorResponse, ToSend as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
ToSend: () => ToSend,
|
|
24
|
+
ToSendError: () => ToSendError,
|
|
25
|
+
default: () => index_default
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
var ToSendError = class extends Error {
|
|
29
|
+
code;
|
|
30
|
+
errors;
|
|
31
|
+
constructor(message, code = 0, errors = {}) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = "ToSendError";
|
|
34
|
+
this.code = code;
|
|
35
|
+
this.errors = errors;
|
|
36
|
+
}
|
|
37
|
+
get isValidationError() {
|
|
38
|
+
return this.code === 422;
|
|
39
|
+
}
|
|
40
|
+
get isAuthenticationError() {
|
|
41
|
+
return this.code === 401 || this.code === 403;
|
|
42
|
+
}
|
|
43
|
+
get isRateLimitError() {
|
|
44
|
+
return this.code === 429;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
var ToSend = class {
|
|
48
|
+
apiKey;
|
|
49
|
+
baseUrl;
|
|
50
|
+
timeout;
|
|
51
|
+
constructor(config) {
|
|
52
|
+
if (typeof config === "string") {
|
|
53
|
+
this.apiKey = config;
|
|
54
|
+
this.baseUrl = "https://api.tosend.com";
|
|
55
|
+
this.timeout = 3e4;
|
|
56
|
+
} else {
|
|
57
|
+
this.apiKey = config.apiKey;
|
|
58
|
+
this.baseUrl = config.baseUrl?.replace(/\/$/, "") ?? "https://api.tosend.com";
|
|
59
|
+
this.timeout = config.timeout ?? 3e4;
|
|
60
|
+
}
|
|
61
|
+
if (!this.apiKey?.trim()) {
|
|
62
|
+
throw new ToSendError("API key is required", 401);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Send a single email.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* const response = await tosend.send({
|
|
71
|
+
* from: { email: 'hello@example.com', name: 'My App' },
|
|
72
|
+
* to: [{ email: 'user@example.com' }],
|
|
73
|
+
* subject: 'Hello!',
|
|
74
|
+
* html: '<p>Welcome!</p>'
|
|
75
|
+
* });
|
|
76
|
+
* console.log(response.message_id);
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
async send(params) {
|
|
80
|
+
this.validateEmailParams(params);
|
|
81
|
+
return this.request("POST", "/v2/emails", params);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Send multiple emails in a single request.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* const response = await tosend.batch([
|
|
89
|
+
* {
|
|
90
|
+
* from: { email: 'hello@example.com' },
|
|
91
|
+
* to: [{ email: 'user1@example.com' }],
|
|
92
|
+
* subject: 'Hello User 1',
|
|
93
|
+
* html: '<p>Hi!</p>'
|
|
94
|
+
* },
|
|
95
|
+
* {
|
|
96
|
+
* from: { email: 'hello@example.com' },
|
|
97
|
+
* to: [{ email: 'user2@example.com' }],
|
|
98
|
+
* subject: 'Hello User 2',
|
|
99
|
+
* html: '<p>Hi!</p>'
|
|
100
|
+
* }
|
|
101
|
+
* ]);
|
|
102
|
+
*
|
|
103
|
+
* response.results.forEach(result => {
|
|
104
|
+
* if (result.status === 'success') {
|
|
105
|
+
* console.log('Sent:', result.message_id);
|
|
106
|
+
* }
|
|
107
|
+
* });
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
async batch(emails) {
|
|
111
|
+
if (!emails?.length) {
|
|
112
|
+
throw new ToSendError("Emails array is required and cannot be empty", 422, {
|
|
113
|
+
emails: { required: "At least one email is required" }
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
emails.forEach((email, index) => {
|
|
117
|
+
try {
|
|
118
|
+
this.validateEmailParams(email);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
if (error instanceof ToSendError) {
|
|
121
|
+
throw new ToSendError(
|
|
122
|
+
`Email at index ${index}: ${error.message}`,
|
|
123
|
+
error.code,
|
|
124
|
+
error.errors
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
return this.request("POST", "/v2/emails/batch", { emails });
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get account information and domains.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* const info = await tosend.getAccountInfo();
|
|
138
|
+
* console.log(info.account.title);
|
|
139
|
+
* console.log(info.account.emails_usage_this_month);
|
|
140
|
+
* info.domains.forEach(d => console.log(d.domain_name, d.verification_status));
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
async getAccountInfo() {
|
|
144
|
+
return this.request("GET", "/v2/info");
|
|
145
|
+
}
|
|
146
|
+
// ==========================================================================
|
|
147
|
+
// Private Methods
|
|
148
|
+
// ==========================================================================
|
|
149
|
+
validateEmailParams(params) {
|
|
150
|
+
const errors = {};
|
|
151
|
+
if (!params.from?.email) {
|
|
152
|
+
errors.from = { required: "From email is required" };
|
|
153
|
+
} else if (!this.isValidEmail(params.from.email)) {
|
|
154
|
+
errors.from = { invalid: "From email is invalid" };
|
|
155
|
+
}
|
|
156
|
+
if (!params.to?.length) {
|
|
157
|
+
errors.to = { required: "To is required" };
|
|
158
|
+
} else {
|
|
159
|
+
const hasValidRecipient = params.to.some(
|
|
160
|
+
(r) => r.email && this.isValidEmail(r.email)
|
|
161
|
+
);
|
|
162
|
+
if (!hasValidRecipient) {
|
|
163
|
+
errors.to = { invalid: "At least one valid recipient email is required" };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (!params.subject) {
|
|
167
|
+
errors.subject = { required: "Subject is required" };
|
|
168
|
+
}
|
|
169
|
+
if (!params.html && !params.text) {
|
|
170
|
+
errors.content = { required: "Either html or text content is required" };
|
|
171
|
+
}
|
|
172
|
+
if (Object.keys(errors).length > 0) {
|
|
173
|
+
const firstError = Object.values(errors)[0];
|
|
174
|
+
const message = Object.values(firstError)[0];
|
|
175
|
+
throw new ToSendError(message, 422, errors);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
isValidEmail(email) {
|
|
179
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
180
|
+
}
|
|
181
|
+
async request(method, endpoint, body) {
|
|
182
|
+
const url = `${this.baseUrl}${endpoint}`;
|
|
183
|
+
const controller = new AbortController();
|
|
184
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
185
|
+
try {
|
|
186
|
+
const response = await fetch(url, {
|
|
187
|
+
method,
|
|
188
|
+
headers: {
|
|
189
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
190
|
+
"Content-Type": "application/json",
|
|
191
|
+
Accept: "application/json"
|
|
192
|
+
},
|
|
193
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
194
|
+
signal: controller.signal
|
|
195
|
+
});
|
|
196
|
+
clearTimeout(timeoutId);
|
|
197
|
+
const data = await response.json();
|
|
198
|
+
if (!response.ok) {
|
|
199
|
+
throw new ToSendError(
|
|
200
|
+
data.message ?? "Unknown error",
|
|
201
|
+
response.status,
|
|
202
|
+
data.errors ?? {}
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
return data;
|
|
206
|
+
} catch (error) {
|
|
207
|
+
clearTimeout(timeoutId);
|
|
208
|
+
if (error instanceof ToSendError) {
|
|
209
|
+
throw error;
|
|
210
|
+
}
|
|
211
|
+
if (error instanceof Error) {
|
|
212
|
+
if (error.name === "AbortError") {
|
|
213
|
+
throw new ToSendError("Request timeout", 408);
|
|
214
|
+
}
|
|
215
|
+
throw new ToSendError(error.message);
|
|
216
|
+
}
|
|
217
|
+
throw new ToSendError("Unknown error");
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
var index_default = ToSend;
|
|
222
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
223
|
+
0 && (module.exports = {
|
|
224
|
+
ToSend,
|
|
225
|
+
ToSendError
|
|
226
|
+
});
|
|
227
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * ToSend Node.js SDK\n *\n * Official SDK for the ToSend email API.\n * @see https://tosend.com/docs\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface Address {\n email: string;\n name?: string;\n}\n\nexport interface Attachment {\n /** MIME type (e.g., 'application/pdf') */\n type: string;\n /** Filename */\n name: string;\n /** Base64 encoded content */\n content: string;\n}\n\nexport interface SendEmailParams {\n /** Sender address */\n from: Address;\n /** Recipients (max 50) */\n to: Address[];\n /** Email subject */\n subject: string;\n /** HTML content */\n html?: string;\n /** Plain text content */\n text?: string;\n /** CC recipients */\n cc?: Address[];\n /** BCC recipients */\n bcc?: Address[];\n /** Reply-to address */\n reply_to?: Address;\n /** Custom headers */\n headers?: Record<string, string>;\n /** File attachments */\n attachments?: Attachment[];\n}\n\nexport interface SendEmailResponse {\n message_id: string;\n}\n\nexport interface BatchEmailResult {\n status: 'success' | 'error' | 'spam';\n message_id?: string;\n message?: string;\n errors?: Record<string, Record<string, string>>;\n}\n\nexport interface BatchEmailResponse {\n results: BatchEmailResult[];\n}\n\nexport interface Domain {\n domain_name: string;\n verification_status: 'pending' | 'verified' | 'failed';\n created_at: string;\n}\n\nexport interface AccountInfo {\n account: {\n title: string;\n plan_type: string;\n status: string;\n emails_usage_this_month: number;\n emails_sent_last_24hrs: number;\n };\n domains: Domain[];\n}\n\nexport interface ToSendErrorResponse {\n error_code: number;\n message: string;\n errors?: Record<string, Record<string, string>>;\n}\n\nexport interface ToSendConfig {\n /** Your ToSend API key */\n apiKey: string;\n /** Custom base URL (optional) */\n baseUrl?: string;\n /** Request timeout in ms (default: 30000) */\n timeout?: number;\n}\n\n// ============================================================================\n// Error Class\n// ============================================================================\n\nexport class ToSendError extends Error {\n readonly code: number;\n readonly errors: Record<string, Record<string, string>>;\n\n constructor(\n message: string,\n code: number = 0,\n errors: Record<string, Record<string, string>> = {}\n ) {\n super(message);\n this.name = 'ToSendError';\n this.code = code;\n this.errors = errors;\n }\n\n get isValidationError(): boolean {\n return this.code === 422;\n }\n\n get isAuthenticationError(): boolean {\n return this.code === 401 || this.code === 403;\n }\n\n get isRateLimitError(): boolean {\n return this.code === 429;\n }\n}\n\n// ============================================================================\n// Main Client\n// ============================================================================\n\nexport class ToSend {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly timeout: number;\n\n constructor(config: string | ToSendConfig) {\n if (typeof config === 'string') {\n this.apiKey = config;\n this.baseUrl = 'https://api.tosend.com';\n this.timeout = 30000;\n } else {\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl?.replace(/\\/$/, '') ?? 'https://api.tosend.com';\n this.timeout = config.timeout ?? 30000;\n }\n\n if (!this.apiKey?.trim()) {\n throw new ToSendError('API key is required', 401);\n }\n }\n\n /**\n * Send a single email.\n *\n * @example\n * ```ts\n * const response = await tosend.send({\n * from: { email: 'hello@example.com', name: 'My App' },\n * to: [{ email: 'user@example.com' }],\n * subject: 'Hello!',\n * html: '<p>Welcome!</p>'\n * });\n * console.log(response.message_id);\n * ```\n */\n async send(params: SendEmailParams): Promise<SendEmailResponse> {\n this.validateEmailParams(params);\n return this.request<SendEmailResponse>('POST', '/v2/emails', params);\n }\n\n /**\n * Send multiple emails in a single request.\n *\n * @example\n * ```ts\n * const response = await tosend.batch([\n * {\n * from: { email: 'hello@example.com' },\n * to: [{ email: 'user1@example.com' }],\n * subject: 'Hello User 1',\n * html: '<p>Hi!</p>'\n * },\n * {\n * from: { email: 'hello@example.com' },\n * to: [{ email: 'user2@example.com' }],\n * subject: 'Hello User 2',\n * html: '<p>Hi!</p>'\n * }\n * ]);\n *\n * response.results.forEach(result => {\n * if (result.status === 'success') {\n * console.log('Sent:', result.message_id);\n * }\n * });\n * ```\n */\n async batch(emails: SendEmailParams[]): Promise<BatchEmailResponse> {\n if (!emails?.length) {\n throw new ToSendError('Emails array is required and cannot be empty', 422, {\n emails: { required: 'At least one email is required' },\n });\n }\n\n emails.forEach((email, index) => {\n try {\n this.validateEmailParams(email);\n } catch (error) {\n if (error instanceof ToSendError) {\n throw new ToSendError(\n `Email at index ${index}: ${error.message}`,\n error.code,\n error.errors\n );\n }\n throw error;\n }\n });\n\n return this.request<BatchEmailResponse>('POST', '/v2/emails/batch', { emails });\n }\n\n /**\n * Get account information and domains.\n *\n * @example\n * ```ts\n * const info = await tosend.getAccountInfo();\n * console.log(info.account.title);\n * console.log(info.account.emails_usage_this_month);\n * info.domains.forEach(d => console.log(d.domain_name, d.verification_status));\n * ```\n */\n async getAccountInfo(): Promise<AccountInfo> {\n return this.request<AccountInfo>('GET', '/v2/info');\n }\n\n // ==========================================================================\n // Private Methods\n // ==========================================================================\n\n private validateEmailParams(params: SendEmailParams): void {\n const errors: Record<string, Record<string, string>> = {};\n\n if (!params.from?.email) {\n errors.from = { required: 'From email is required' };\n } else if (!this.isValidEmail(params.from.email)) {\n errors.from = { invalid: 'From email is invalid' };\n }\n\n if (!params.to?.length) {\n errors.to = { required: 'To is required' };\n } else {\n const hasValidRecipient = params.to.some(\n (r) => r.email && this.isValidEmail(r.email)\n );\n if (!hasValidRecipient) {\n errors.to = { invalid: 'At least one valid recipient email is required' };\n }\n }\n\n if (!params.subject) {\n errors.subject = { required: 'Subject is required' };\n }\n\n if (!params.html && !params.text) {\n errors.content = { required: 'Either html or text content is required' };\n }\n\n if (Object.keys(errors).length > 0) {\n const firstError = Object.values(errors)[0];\n const message = Object.values(firstError)[0];\n throw new ToSendError(message, 422, errors);\n }\n }\n\n private isValidEmail(email: string): boolean {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email);\n }\n\n private async request<T>(\n method: 'GET' | 'POST',\n endpoint: string,\n body?: unknown\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n const data = await response.json() as T & { message?: string; errors?: Record<string, Record<string, string>> };\n\n if (!response.ok) {\n throw new ToSendError(\n data.message ?? 'Unknown error',\n response.status,\n data.errors ?? {}\n );\n }\n\n return data;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof ToSendError) {\n throw error;\n }\n\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new ToSendError('Request timeout', 408);\n }\n throw new ToSendError(error.message);\n }\n\n throw new ToSendError('Unknown error');\n }\n }\n}\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default ToSend;\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var ToSendError = class extends Error {
|
|
3
|
+
code;
|
|
4
|
+
errors;
|
|
5
|
+
constructor(message, code = 0, errors = {}) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "ToSendError";
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.errors = errors;
|
|
10
|
+
}
|
|
11
|
+
get isValidationError() {
|
|
12
|
+
return this.code === 422;
|
|
13
|
+
}
|
|
14
|
+
get isAuthenticationError() {
|
|
15
|
+
return this.code === 401 || this.code === 403;
|
|
16
|
+
}
|
|
17
|
+
get isRateLimitError() {
|
|
18
|
+
return this.code === 429;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var ToSend = class {
|
|
22
|
+
apiKey;
|
|
23
|
+
baseUrl;
|
|
24
|
+
timeout;
|
|
25
|
+
constructor(config) {
|
|
26
|
+
if (typeof config === "string") {
|
|
27
|
+
this.apiKey = config;
|
|
28
|
+
this.baseUrl = "https://api.tosend.com";
|
|
29
|
+
this.timeout = 3e4;
|
|
30
|
+
} else {
|
|
31
|
+
this.apiKey = config.apiKey;
|
|
32
|
+
this.baseUrl = config.baseUrl?.replace(/\/$/, "") ?? "https://api.tosend.com";
|
|
33
|
+
this.timeout = config.timeout ?? 3e4;
|
|
34
|
+
}
|
|
35
|
+
if (!this.apiKey?.trim()) {
|
|
36
|
+
throw new ToSendError("API key is required", 401);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Send a single email.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* const response = await tosend.send({
|
|
45
|
+
* from: { email: 'hello@example.com', name: 'My App' },
|
|
46
|
+
* to: [{ email: 'user@example.com' }],
|
|
47
|
+
* subject: 'Hello!',
|
|
48
|
+
* html: '<p>Welcome!</p>'
|
|
49
|
+
* });
|
|
50
|
+
* console.log(response.message_id);
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
async send(params) {
|
|
54
|
+
this.validateEmailParams(params);
|
|
55
|
+
return this.request("POST", "/v2/emails", params);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Send multiple emails in a single request.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* const response = await tosend.batch([
|
|
63
|
+
* {
|
|
64
|
+
* from: { email: 'hello@example.com' },
|
|
65
|
+
* to: [{ email: 'user1@example.com' }],
|
|
66
|
+
* subject: 'Hello User 1',
|
|
67
|
+
* html: '<p>Hi!</p>'
|
|
68
|
+
* },
|
|
69
|
+
* {
|
|
70
|
+
* from: { email: 'hello@example.com' },
|
|
71
|
+
* to: [{ email: 'user2@example.com' }],
|
|
72
|
+
* subject: 'Hello User 2',
|
|
73
|
+
* html: '<p>Hi!</p>'
|
|
74
|
+
* }
|
|
75
|
+
* ]);
|
|
76
|
+
*
|
|
77
|
+
* response.results.forEach(result => {
|
|
78
|
+
* if (result.status === 'success') {
|
|
79
|
+
* console.log('Sent:', result.message_id);
|
|
80
|
+
* }
|
|
81
|
+
* });
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
async batch(emails) {
|
|
85
|
+
if (!emails?.length) {
|
|
86
|
+
throw new ToSendError("Emails array is required and cannot be empty", 422, {
|
|
87
|
+
emails: { required: "At least one email is required" }
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
emails.forEach((email, index) => {
|
|
91
|
+
try {
|
|
92
|
+
this.validateEmailParams(email);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
if (error instanceof ToSendError) {
|
|
95
|
+
throw new ToSendError(
|
|
96
|
+
`Email at index ${index}: ${error.message}`,
|
|
97
|
+
error.code,
|
|
98
|
+
error.errors
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
return this.request("POST", "/v2/emails/batch", { emails });
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get account information and domains.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* const info = await tosend.getAccountInfo();
|
|
112
|
+
* console.log(info.account.title);
|
|
113
|
+
* console.log(info.account.emails_usage_this_month);
|
|
114
|
+
* info.domains.forEach(d => console.log(d.domain_name, d.verification_status));
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
async getAccountInfo() {
|
|
118
|
+
return this.request("GET", "/v2/info");
|
|
119
|
+
}
|
|
120
|
+
// ==========================================================================
|
|
121
|
+
// Private Methods
|
|
122
|
+
// ==========================================================================
|
|
123
|
+
validateEmailParams(params) {
|
|
124
|
+
const errors = {};
|
|
125
|
+
if (!params.from?.email) {
|
|
126
|
+
errors.from = { required: "From email is required" };
|
|
127
|
+
} else if (!this.isValidEmail(params.from.email)) {
|
|
128
|
+
errors.from = { invalid: "From email is invalid" };
|
|
129
|
+
}
|
|
130
|
+
if (!params.to?.length) {
|
|
131
|
+
errors.to = { required: "To is required" };
|
|
132
|
+
} else {
|
|
133
|
+
const hasValidRecipient = params.to.some(
|
|
134
|
+
(r) => r.email && this.isValidEmail(r.email)
|
|
135
|
+
);
|
|
136
|
+
if (!hasValidRecipient) {
|
|
137
|
+
errors.to = { invalid: "At least one valid recipient email is required" };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (!params.subject) {
|
|
141
|
+
errors.subject = { required: "Subject is required" };
|
|
142
|
+
}
|
|
143
|
+
if (!params.html && !params.text) {
|
|
144
|
+
errors.content = { required: "Either html or text content is required" };
|
|
145
|
+
}
|
|
146
|
+
if (Object.keys(errors).length > 0) {
|
|
147
|
+
const firstError = Object.values(errors)[0];
|
|
148
|
+
const message = Object.values(firstError)[0];
|
|
149
|
+
throw new ToSendError(message, 422, errors);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
isValidEmail(email) {
|
|
153
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
154
|
+
}
|
|
155
|
+
async request(method, endpoint, body) {
|
|
156
|
+
const url = `${this.baseUrl}${endpoint}`;
|
|
157
|
+
const controller = new AbortController();
|
|
158
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
159
|
+
try {
|
|
160
|
+
const response = await fetch(url, {
|
|
161
|
+
method,
|
|
162
|
+
headers: {
|
|
163
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
164
|
+
"Content-Type": "application/json",
|
|
165
|
+
Accept: "application/json"
|
|
166
|
+
},
|
|
167
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
168
|
+
signal: controller.signal
|
|
169
|
+
});
|
|
170
|
+
clearTimeout(timeoutId);
|
|
171
|
+
const data = await response.json();
|
|
172
|
+
if (!response.ok) {
|
|
173
|
+
throw new ToSendError(
|
|
174
|
+
data.message ?? "Unknown error",
|
|
175
|
+
response.status,
|
|
176
|
+
data.errors ?? {}
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
return data;
|
|
180
|
+
} catch (error) {
|
|
181
|
+
clearTimeout(timeoutId);
|
|
182
|
+
if (error instanceof ToSendError) {
|
|
183
|
+
throw error;
|
|
184
|
+
}
|
|
185
|
+
if (error instanceof Error) {
|
|
186
|
+
if (error.name === "AbortError") {
|
|
187
|
+
throw new ToSendError("Request timeout", 408);
|
|
188
|
+
}
|
|
189
|
+
throw new ToSendError(error.message);
|
|
190
|
+
}
|
|
191
|
+
throw new ToSendError("Unknown error");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
var index_default = ToSend;
|
|
196
|
+
export {
|
|
197
|
+
ToSend,
|
|
198
|
+
ToSendError,
|
|
199
|
+
index_default as default
|
|
200
|
+
};
|
|
201
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * ToSend Node.js SDK\n *\n * Official SDK for the ToSend email API.\n * @see https://tosend.com/docs\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface Address {\n email: string;\n name?: string;\n}\n\nexport interface Attachment {\n /** MIME type (e.g., 'application/pdf') */\n type: string;\n /** Filename */\n name: string;\n /** Base64 encoded content */\n content: string;\n}\n\nexport interface SendEmailParams {\n /** Sender address */\n from: Address;\n /** Recipients (max 50) */\n to: Address[];\n /** Email subject */\n subject: string;\n /** HTML content */\n html?: string;\n /** Plain text content */\n text?: string;\n /** CC recipients */\n cc?: Address[];\n /** BCC recipients */\n bcc?: Address[];\n /** Reply-to address */\n reply_to?: Address;\n /** Custom headers */\n headers?: Record<string, string>;\n /** File attachments */\n attachments?: Attachment[];\n}\n\nexport interface SendEmailResponse {\n message_id: string;\n}\n\nexport interface BatchEmailResult {\n status: 'success' | 'error' | 'spam';\n message_id?: string;\n message?: string;\n errors?: Record<string, Record<string, string>>;\n}\n\nexport interface BatchEmailResponse {\n results: BatchEmailResult[];\n}\n\nexport interface Domain {\n domain_name: string;\n verification_status: 'pending' | 'verified' | 'failed';\n created_at: string;\n}\n\nexport interface AccountInfo {\n account: {\n title: string;\n plan_type: string;\n status: string;\n emails_usage_this_month: number;\n emails_sent_last_24hrs: number;\n };\n domains: Domain[];\n}\n\nexport interface ToSendErrorResponse {\n error_code: number;\n message: string;\n errors?: Record<string, Record<string, string>>;\n}\n\nexport interface ToSendConfig {\n /** Your ToSend API key */\n apiKey: string;\n /** Custom base URL (optional) */\n baseUrl?: string;\n /** Request timeout in ms (default: 30000) */\n timeout?: number;\n}\n\n// ============================================================================\n// Error Class\n// ============================================================================\n\nexport class ToSendError extends Error {\n readonly code: number;\n readonly errors: Record<string, Record<string, string>>;\n\n constructor(\n message: string,\n code: number = 0,\n errors: Record<string, Record<string, string>> = {}\n ) {\n super(message);\n this.name = 'ToSendError';\n this.code = code;\n this.errors = errors;\n }\n\n get isValidationError(): boolean {\n return this.code === 422;\n }\n\n get isAuthenticationError(): boolean {\n return this.code === 401 || this.code === 403;\n }\n\n get isRateLimitError(): boolean {\n return this.code === 429;\n }\n}\n\n// ============================================================================\n// Main Client\n// ============================================================================\n\nexport class ToSend {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly timeout: number;\n\n constructor(config: string | ToSendConfig) {\n if (typeof config === 'string') {\n this.apiKey = config;\n this.baseUrl = 'https://api.tosend.com';\n this.timeout = 30000;\n } else {\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl?.replace(/\\/$/, '') ?? 'https://api.tosend.com';\n this.timeout = config.timeout ?? 30000;\n }\n\n if (!this.apiKey?.trim()) {\n throw new ToSendError('API key is required', 401);\n }\n }\n\n /**\n * Send a single email.\n *\n * @example\n * ```ts\n * const response = await tosend.send({\n * from: { email: 'hello@example.com', name: 'My App' },\n * to: [{ email: 'user@example.com' }],\n * subject: 'Hello!',\n * html: '<p>Welcome!</p>'\n * });\n * console.log(response.message_id);\n * ```\n */\n async send(params: SendEmailParams): Promise<SendEmailResponse> {\n this.validateEmailParams(params);\n return this.request<SendEmailResponse>('POST', '/v2/emails', params);\n }\n\n /**\n * Send multiple emails in a single request.\n *\n * @example\n * ```ts\n * const response = await tosend.batch([\n * {\n * from: { email: 'hello@example.com' },\n * to: [{ email: 'user1@example.com' }],\n * subject: 'Hello User 1',\n * html: '<p>Hi!</p>'\n * },\n * {\n * from: { email: 'hello@example.com' },\n * to: [{ email: 'user2@example.com' }],\n * subject: 'Hello User 2',\n * html: '<p>Hi!</p>'\n * }\n * ]);\n *\n * response.results.forEach(result => {\n * if (result.status === 'success') {\n * console.log('Sent:', result.message_id);\n * }\n * });\n * ```\n */\n async batch(emails: SendEmailParams[]): Promise<BatchEmailResponse> {\n if (!emails?.length) {\n throw new ToSendError('Emails array is required and cannot be empty', 422, {\n emails: { required: 'At least one email is required' },\n });\n }\n\n emails.forEach((email, index) => {\n try {\n this.validateEmailParams(email);\n } catch (error) {\n if (error instanceof ToSendError) {\n throw new ToSendError(\n `Email at index ${index}: ${error.message}`,\n error.code,\n error.errors\n );\n }\n throw error;\n }\n });\n\n return this.request<BatchEmailResponse>('POST', '/v2/emails/batch', { emails });\n }\n\n /**\n * Get account information and domains.\n *\n * @example\n * ```ts\n * const info = await tosend.getAccountInfo();\n * console.log(info.account.title);\n * console.log(info.account.emails_usage_this_month);\n * info.domains.forEach(d => console.log(d.domain_name, d.verification_status));\n * ```\n */\n async getAccountInfo(): Promise<AccountInfo> {\n return this.request<AccountInfo>('GET', '/v2/info');\n }\n\n // ==========================================================================\n // Private Methods\n // ==========================================================================\n\n private validateEmailParams(params: SendEmailParams): void {\n const errors: Record<string, Record<string, string>> = {};\n\n if (!params.from?.email) {\n errors.from = { required: 'From email is required' };\n } else if (!this.isValidEmail(params.from.email)) {\n errors.from = { invalid: 'From email is invalid' };\n }\n\n if (!params.to?.length) {\n errors.to = { required: 'To is required' };\n } else {\n const hasValidRecipient = params.to.some(\n (r) => r.email && this.isValidEmail(r.email)\n );\n if (!hasValidRecipient) {\n errors.to = { invalid: 'At least one valid recipient email is required' };\n }\n }\n\n if (!params.subject) {\n errors.subject = { required: 'Subject is required' };\n }\n\n if (!params.html && !params.text) {\n errors.content = { required: 'Either html or text content is required' };\n }\n\n if (Object.keys(errors).length > 0) {\n const firstError = Object.values(errors)[0];\n const message = Object.values(firstError)[0];\n throw new ToSendError(message, 422, errors);\n }\n }\n\n private isValidEmail(email: string): boolean {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email);\n }\n\n private async request<T>(\n method: 'GET' | 'POST',\n endpoint: string,\n body?: unknown\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n const data = await response.json() as T & { message?: string; errors?: Record<string, Record<string, string>> };\n\n if (!response.ok) {\n throw new ToSendError(\n data.message ?? 'Unknown error',\n response.status,\n data.errors ?? {}\n );\n }\n\n return data;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof ToSendError) {\n throw error;\n }\n\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new ToSendError('Request timeout', 408);\n }\n throw new ToSendError(error.message);\n }\n\n throw new ToSendError('Unknown error');\n }\n }\n}\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default ToSend;\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tosend",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official Node.js SDK for the ToSend email API",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.mjs",
|
|
11
|
+
"require": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsup",
|
|
20
|
+
"dev": "tsup --watch",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"test:watch": "vitest",
|
|
23
|
+
"lint": "eslint src/",
|
|
24
|
+
"typecheck": "tsc --noEmit",
|
|
25
|
+
"prepublishOnly": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"email",
|
|
29
|
+
"api",
|
|
30
|
+
"tosend",
|
|
31
|
+
"transactional",
|
|
32
|
+
"mail",
|
|
33
|
+
"smtp"
|
|
34
|
+
],
|
|
35
|
+
"author": "ToSend <support@tosend.com>",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"homepage": "https://tosend.com",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/tosend/tosend-node.git"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/tosend/tosend-node/issues"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^20.10.0",
|
|
50
|
+
"tsup": "^8.0.1",
|
|
51
|
+
"typescript": "^5.3.0",
|
|
52
|
+
"vitest": "^1.0.0"
|
|
53
|
+
}
|
|
54
|
+
}
|