@geekmidas/emailkit 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,423 @@
1
+ # @geekmidas/emailkit
2
+
3
+ Type-safe email client with SMTP support and React templates.
4
+
5
+ ## Features
6
+
7
+ - **Type-Safe Templates**: Templates are provided at construction time with full TypeScript inference for both template names and their corresponding props
8
+ - **SMTP Support**: Works with any SMTP server via nodemailer configuration
9
+ - **React Templates**: Uses `react-dom/server` to render React components to HTML
10
+ - **Built-in Templates**: Includes common email templates (welcome, password reset, notifications)
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ pnpm add @geekmidas/emailkit
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ```typescript
21
+ import { createEmailClient } from '@geekmidas/emailkit';
22
+
23
+ // Define your templates with props
24
+ const WelcomeEmail = ({ name, confirmationUrl }: {
25
+ name: string;
26
+ confirmationUrl?: string;
27
+ }) => (
28
+ <div style={{ fontFamily: 'Arial, sans-serif', maxWidth: '600px' }}>
29
+ <h1>Welcome, {name}!</h1>
30
+ <p>We're excited to have you on board.</p>
31
+ {confirmationUrl && (
32
+ <p>
33
+ <a href={confirmationUrl} style={{
34
+ backgroundColor: '#007bff',
35
+ color: 'white',
36
+ padding: '10px 20px',
37
+ textDecoration: 'none',
38
+ borderRadius: '4px'
39
+ }}>
40
+ Confirm Email
41
+ </a>
42
+ </p>
43
+ )}
44
+ </div>
45
+ );
46
+
47
+ const templates = {
48
+ welcome: WelcomeEmail,
49
+ };
50
+
51
+ // Create client with templates - types are fully inferred
52
+ const client = createEmailClient({
53
+ smtp: {
54
+ host: 'smtp.example.com',
55
+ port: 587,
56
+ auth: {
57
+ user: 'user@example.com',
58
+ pass: 'password',
59
+ },
60
+ },
61
+ templates,
62
+ defaults: {
63
+ from: 'noreply@example.com',
64
+ },
65
+ });
66
+
67
+ // Send email with full type safety
68
+ await client.sendTemplate('welcome', {
69
+ from: 'welcome@example.com',
70
+ to: 'user@example.com',
71
+ subject: 'Welcome to our service!',
72
+ props: {
73
+ name: 'John Doe',
74
+ confirmationUrl: 'https://example.com/confirm/123',
75
+ },
76
+ });
77
+ ```
78
+
79
+ ## API Reference
80
+
81
+ ### `createEmailClient<T>(config: EmailClientConfig<T>): SMTPClient<T>`
82
+
83
+ Creates a new email client with type-safe template support.
84
+
85
+ #### Configuration
86
+
87
+ ```typescript
88
+ interface EmailClientConfig<T extends TemplateRecord> {
89
+ smtp: SMTPConfig;
90
+ templates: T;
91
+ defaults?: {
92
+ from?: string | Address;
93
+ replyTo?: string | Address;
94
+ };
95
+ }
96
+
97
+ interface SMTPConfig {
98
+ host: string;
99
+ port: number;
100
+ secure?: boolean;
101
+ auth?: {
102
+ user: string;
103
+ pass: string;
104
+ };
105
+ tls?: {
106
+ rejectUnauthorized?: boolean;
107
+ servername?: string;
108
+ };
109
+ pool?: boolean;
110
+ maxConnections?: number;
111
+ maxMessages?: number;
112
+ rateLimit?: number;
113
+ logger?: boolean;
114
+ debug?: boolean;
115
+ }
116
+ ```
117
+
118
+ ### Client Methods
119
+
120
+ #### `send(options: PlainEmailOptions): Promise<SendResult>`
121
+
122
+ Send a plain text or HTML email.
123
+
124
+ ```typescript
125
+ await client.send({
126
+ from: 'info@example.com',
127
+ to: 'user@example.com',
128
+ subject: 'Plain email',
129
+ text: 'This is a plain text email',
130
+ html: '<p>This is an HTML email</p>',
131
+ });
132
+ ```
133
+
134
+ #### `sendTemplate<K>(template: K, options): Promise<SendResult>`
135
+
136
+ Send an email using a React template with type-safe props.
137
+
138
+ ```typescript
139
+ await client.sendTemplate('welcome', {
140
+ from: 'welcome@example.com',
141
+ to: 'user@example.com',
142
+ subject: 'Welcome!',
143
+ props: { name: 'John', confirmationUrl: 'https://...' },
144
+ });
145
+ ```
146
+
147
+ #### `verify(): Promise<boolean>`
148
+
149
+ Verify the SMTP connection.
150
+
151
+ #### `close(): Promise<void>`
152
+
153
+ Close the SMTP connection.
154
+
155
+ #### `getTemplateNames(): string[]`
156
+
157
+ Get available template names.
158
+
159
+ ## Built-in Template Examples
160
+
161
+ ### Welcome Email
162
+
163
+ ```tsx
164
+ interface WelcomeEmailProps {
165
+ name: string;
166
+ confirmationUrl?: string;
167
+ }
168
+
169
+ const WelcomeEmail = ({ name, confirmationUrl }: WelcomeEmailProps) => (
170
+ <html>
171
+ <head>
172
+ <meta charSet="utf-8" />
173
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
174
+ <title>Welcome!</title>
175
+ </head>
176
+ <body style={{ margin: 0, padding: 0, backgroundColor: '#f4f4f4' }}>
177
+ <div style={{
178
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
179
+ lineHeight: 1.6,
180
+ color: '#333',
181
+ maxWidth: '600px',
182
+ margin: '0 auto',
183
+ padding: '20px',
184
+ }}>
185
+ <h1 style={{ color: '#2c3e50', marginBottom: '20px' }}>
186
+ Welcome, {name}!
187
+ </h1>
188
+ <p>
189
+ We're excited to have you on board. Your account has been successfully created.
190
+ </p>
191
+ {confirmationUrl && (
192
+ <>
193
+ <p>Please confirm your email address by clicking the button below:</p>
194
+ <p style={{ textAlign: 'center', margin: '30px 0' }}>
195
+ <a href={confirmationUrl} style={{
196
+ display: 'inline-block',
197
+ padding: '12px 24px',
198
+ backgroundColor: '#3498db',
199
+ color: '#ffffff',
200
+ textDecoration: 'none',
201
+ borderRadius: '4px',
202
+ fontWeight: 'bold',
203
+ }}>
204
+ Confirm Email
205
+ </a>
206
+ </p>
207
+ </>
208
+ )}
209
+ <div style={{
210
+ marginTop: '40px',
211
+ paddingTop: '20px',
212
+ borderTop: '1px solid #eee',
213
+ fontSize: '14px',
214
+ color: '#666',
215
+ }}>
216
+ <p>If you have any questions, feel free to reply to this email.</p>
217
+ <p>Best regards,<br />The Team</p>
218
+ </div>
219
+ </div>
220
+ </body>
221
+ </html>
222
+ );
223
+ ```
224
+
225
+ ### Password Reset Email
226
+
227
+ ```tsx
228
+ interface PasswordResetEmailProps {
229
+ name: string;
230
+ resetUrl: string;
231
+ expiresIn: string;
232
+ }
233
+
234
+ const PasswordResetEmail = ({ name, resetUrl, expiresIn }: PasswordResetEmailProps) => (
235
+ <html>
236
+ <head>
237
+ <meta charSet="utf-8" />
238
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
239
+ <title>Password Reset Request</title>
240
+ </head>
241
+ <body style={{ margin: 0, padding: 0, backgroundColor: '#f4f4f4' }}>
242
+ <div style={{
243
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
244
+ lineHeight: 1.6,
245
+ color: '#333',
246
+ maxWidth: '600px',
247
+ margin: '0 auto',
248
+ padding: '20px',
249
+ }}>
250
+ <h1 style={{ color: '#2c3e50', marginBottom: '20px' }}>
251
+ Password Reset Request
252
+ </h1>
253
+ <p>Hi {name},</p>
254
+ <p>
255
+ We received a request to reset your password. Click the button below to create a new password:
256
+ </p>
257
+ <p style={{ textAlign: 'center', margin: '30px 0' }}>
258
+ <a href={resetUrl} style={{
259
+ display: 'inline-block',
260
+ padding: '12px 24px',
261
+ backgroundColor: '#3498db',
262
+ color: '#ffffff',
263
+ textDecoration: 'none',
264
+ borderRadius: '4px',
265
+ fontWeight: 'bold',
266
+ }}>
267
+ Reset Password
268
+ </a>
269
+ </p>
270
+ <p>
271
+ This link will expire in {expiresIn}. If you didn't request a password reset,
272
+ you can safely ignore this email.
273
+ </p>
274
+ <div style={{
275
+ marginTop: '40px',
276
+ paddingTop: '20px',
277
+ borderTop: '1px solid #eee',
278
+ fontSize: '14px',
279
+ color: '#666',
280
+ }}>
281
+ <p>For security reasons, this link can only be used once.</p>
282
+ </div>
283
+ </div>
284
+ </body>
285
+ </html>
286
+ );
287
+ ```
288
+
289
+ ### Notification Email
290
+
291
+ ```tsx
292
+ interface NotificationEmailProps {
293
+ name: string;
294
+ title: string;
295
+ message: string;
296
+ actionUrl?: string;
297
+ actionText?: string;
298
+ }
299
+
300
+ const NotificationEmail = ({
301
+ name,
302
+ title,
303
+ message,
304
+ actionUrl,
305
+ actionText = 'View Details'
306
+ }: NotificationEmailProps) => (
307
+ <html>
308
+ <head>
309
+ <meta charSet="utf-8" />
310
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
311
+ <title>{title}</title>
312
+ </head>
313
+ <body style={{ margin: 0, padding: 0, backgroundColor: '#f4f4f4' }}>
314
+ <div style={{
315
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
316
+ lineHeight: 1.6,
317
+ color: '#333',
318
+ maxWidth: '600px',
319
+ margin: '0 auto',
320
+ padding: '20px',
321
+ }}>
322
+ <h1 style={{ color: '#2c3e50', marginBottom: '20px' }}>
323
+ {title}
324
+ </h1>
325
+ <p>Hi {name},</p>
326
+ <p>{message}</p>
327
+ {actionUrl && (
328
+ <p style={{ textAlign: 'center', margin: '30px 0' }}>
329
+ <a href={actionUrl} style={{
330
+ display: 'inline-block',
331
+ padding: '12px 24px',
332
+ backgroundColor: '#3498db',
333
+ color: '#ffffff',
334
+ textDecoration: 'none',
335
+ borderRadius: '4px',
336
+ fontWeight: 'bold',
337
+ }}>
338
+ {actionText}
339
+ </a>
340
+ </p>
341
+ )}
342
+ <div style={{
343
+ marginTop: '40px',
344
+ paddingTop: '20px',
345
+ borderTop: '1px solid #eee',
346
+ fontSize: '14px',
347
+ color: '#666',
348
+ }}>
349
+ <p>This is an automated notification from our system.</p>
350
+ </div>
351
+ </div>
352
+ </body>
353
+ </html>
354
+ );
355
+ ```
356
+
357
+ ## Multiple Templates Example
358
+
359
+ ```typescript
360
+ import { createEmailClient } from '@geekmidas/emailkit';
361
+
362
+ const templates = {
363
+ welcome: WelcomeEmail,
364
+ passwordReset: PasswordResetEmail,
365
+ notification: NotificationEmail,
366
+ };
367
+
368
+ const client = createEmailClient({
369
+ smtp: {
370
+ host: 'smtp.example.com',
371
+ port: 587,
372
+ auth: {
373
+ user: 'user@example.com',
374
+ pass: 'password',
375
+ },
376
+ },
377
+ templates,
378
+ defaults: {
379
+ from: 'noreply@example.com',
380
+ },
381
+ });
382
+
383
+ // All template names and props are fully type-safe
384
+ await client.sendTemplate('welcome', {
385
+ from: 'welcome@example.com',
386
+ to: 'user@example.com',
387
+ subject: 'Welcome to our service!',
388
+ props: { name: 'John Doe', confirmationUrl: 'https://example.com/confirm/123' },
389
+ });
390
+
391
+ await client.sendTemplate('passwordReset', {
392
+ from: 'security@example.com',
393
+ to: 'user@example.com',
394
+ subject: 'Reset your password',
395
+ props: { name: 'John Doe', resetUrl: 'https://example.com/reset/456', expiresIn: '24 hours' },
396
+ });
397
+
398
+ await client.sendTemplate('notification', {
399
+ from: 'notifications@example.com',
400
+ to: 'user@example.com',
401
+ subject: 'Important notification',
402
+ props: {
403
+ name: 'John Doe',
404
+ title: 'Account Update',
405
+ message: 'Your account settings have been updated.',
406
+ actionUrl: 'https://example.com/settings',
407
+ actionText: 'View Settings'
408
+ },
409
+ });
410
+ ```
411
+
412
+ ## TypeScript Support
413
+
414
+ The library provides full TypeScript support with:
415
+
416
+ - **Template name inference** - Only valid template names are accepted
417
+ - **Props type checking** - Props are validated based on the template's prop types
418
+ - **Autocomplete support** - IDE autocomplete for template names and props
419
+ - **Compile-time safety** - Catch template and prop errors at build time
420
+
421
+ ## License
422
+
423
+ MIT