payload-plugin-newsletter 0.1.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.
Files changed (124) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/CLAUDE.md +110 -0
  3. package/FEEDBACK.md +148 -0
  4. package/LICENSE +21 -0
  5. package/README-DEVELOPMENT.md +80 -0
  6. package/README.md +430 -0
  7. package/dist/.tsbuildinfo +1 -0
  8. package/dist/collections/Subscribers.d.ts +4 -0
  9. package/dist/collections/Subscribers.d.ts.map +1 -0
  10. package/dist/components/MagicLinkVerify.d.ts +27 -0
  11. package/dist/components/MagicLinkVerify.d.ts.map +1 -0
  12. package/dist/components/NewsletterForm.d.ts +5 -0
  13. package/dist/components/NewsletterForm.d.ts.map +1 -0
  14. package/dist/components/PreferencesForm.d.ts +5 -0
  15. package/dist/components/PreferencesForm.d.ts.map +1 -0
  16. package/dist/components/index.d.ts +5 -0
  17. package/dist/components/index.d.ts.map +1 -0
  18. package/dist/endpoints/index.d.ts +4 -0
  19. package/dist/endpoints/index.d.ts.map +1 -0
  20. package/dist/endpoints/preferences.d.ts +5 -0
  21. package/dist/endpoints/preferences.d.ts.map +1 -0
  22. package/dist/endpoints/subscribe.d.ts +4 -0
  23. package/dist/endpoints/subscribe.d.ts.map +1 -0
  24. package/dist/endpoints/unsubscribe.d.ts +4 -0
  25. package/dist/endpoints/unsubscribe.d.ts.map +1 -0
  26. package/dist/endpoints/verify-magic-link.d.ts +4 -0
  27. package/dist/endpoints/verify-magic-link.d.ts.map +1 -0
  28. package/dist/exports/client.d.ts +6 -0
  29. package/dist/exports/client.d.ts.map +1 -0
  30. package/dist/exports/components.d.ts +2 -0
  31. package/dist/exports/components.d.ts.map +1 -0
  32. package/dist/exports/types.d.ts +2 -0
  33. package/dist/exports/types.d.ts.map +1 -0
  34. package/dist/fields/newsletterScheduling.d.ts +4 -0
  35. package/dist/fields/newsletterScheduling.d.ts.map +1 -0
  36. package/dist/globals/EmailSettings.d.ts +4 -0
  37. package/dist/globals/EmailSettings.d.ts.map +1 -0
  38. package/dist/hooks/useNewsletterAuth.d.ts +16 -0
  39. package/dist/hooks/useNewsletterAuth.d.ts.map +1 -0
  40. package/dist/index.d.ts +10 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/providers/broadcast.d.ts +19 -0
  43. package/dist/providers/broadcast.d.ts.map +1 -0
  44. package/dist/providers/index.d.ts +23 -0
  45. package/dist/providers/index.d.ts.map +1 -0
  46. package/dist/providers/resend.d.ts +20 -0
  47. package/dist/providers/resend.d.ts.map +1 -0
  48. package/dist/providers/types.d.ts +46 -0
  49. package/dist/providers/types.d.ts.map +1 -0
  50. package/dist/src/collections/Subscribers.js +344 -0
  51. package/dist/src/collections/Subscribers.js.map +1 -0
  52. package/dist/src/components/MagicLinkVerify.js +180 -0
  53. package/dist/src/components/MagicLinkVerify.js.map +1 -0
  54. package/dist/src/components/NewsletterForm.js +326 -0
  55. package/dist/src/components/NewsletterForm.js.map +1 -0
  56. package/dist/src/components/PreferencesForm.js +524 -0
  57. package/dist/src/components/PreferencesForm.js.map +1 -0
  58. package/dist/src/components/index.js +5 -0
  59. package/dist/src/components/index.js.map +1 -0
  60. package/dist/src/endpoints/index.js +17 -0
  61. package/dist/src/endpoints/index.js.map +1 -0
  62. package/dist/src/endpoints/preferences.js +124 -0
  63. package/dist/src/endpoints/preferences.js.map +1 -0
  64. package/dist/src/endpoints/subscribe.js +140 -0
  65. package/dist/src/endpoints/subscribe.js.map +1 -0
  66. package/dist/src/endpoints/unsubscribe.js +97 -0
  67. package/dist/src/endpoints/unsubscribe.js.map +1 -0
  68. package/dist/src/endpoints/verify-magic-link.js +93 -0
  69. package/dist/src/endpoints/verify-magic-link.js.map +1 -0
  70. package/dist/src/exports/client.js +7 -0
  71. package/dist/src/exports/client.js.map +1 -0
  72. package/dist/src/exports/components.js +6 -0
  73. package/dist/src/exports/components.js.map +1 -0
  74. package/dist/src/exports/types.js +3 -0
  75. package/dist/src/exports/types.js.map +1 -0
  76. package/dist/src/fields/newsletterScheduling.js +195 -0
  77. package/dist/src/fields/newsletterScheduling.js.map +1 -0
  78. package/dist/src/globals/EmailSettings.js +252 -0
  79. package/dist/src/globals/EmailSettings.js.map +1 -0
  80. package/dist/src/hooks/useNewsletterAuth.js +112 -0
  81. package/dist/src/hooks/useNewsletterAuth.js.map +1 -0
  82. package/dist/src/index.js +124 -0
  83. package/dist/src/index.js.map +1 -0
  84. package/dist/src/providers/broadcast.js +158 -0
  85. package/dist/src/providers/broadcast.js.map +1 -0
  86. package/dist/src/providers/index.js +63 -0
  87. package/dist/src/providers/index.js.map +1 -0
  88. package/dist/src/providers/resend.js +122 -0
  89. package/dist/src/providers/resend.js.map +1 -0
  90. package/dist/src/providers/types.js +12 -0
  91. package/dist/src/providers/types.js.map +1 -0
  92. package/dist/src/templates/BaseTemplate.js +105 -0
  93. package/dist/src/templates/BaseTemplate.js.map +1 -0
  94. package/dist/src/templates/MagicLinkTemplate.js +178 -0
  95. package/dist/src/templates/MagicLinkTemplate.js.map +1 -0
  96. package/dist/src/templates/NewsletterTemplate.js +150 -0
  97. package/dist/src/templates/NewsletterTemplate.js.map +1 -0
  98. package/dist/src/templates/WelcomeTemplate.js +192 -0
  99. package/dist/src/templates/WelcomeTemplate.js.map +1 -0
  100. package/dist/src/templates/index.js +6 -0
  101. package/dist/src/templates/index.js.map +1 -0
  102. package/dist/src/types/index.js +3 -0
  103. package/dist/src/types/index.js.map +1 -0
  104. package/dist/src/utils/jwt.js +91 -0
  105. package/dist/src/utils/jwt.js.map +1 -0
  106. package/dist/src/utils/validation.js +66 -0
  107. package/dist/src/utils/validation.js.map +1 -0
  108. package/dist/templates/BaseTemplate.d.ts +45 -0
  109. package/dist/templates/BaseTemplate.d.ts.map +1 -0
  110. package/dist/templates/MagicLinkTemplate.d.ts +67 -0
  111. package/dist/templates/MagicLinkTemplate.d.ts.map +1 -0
  112. package/dist/templates/NewsletterTemplate.d.ts +112 -0
  113. package/dist/templates/NewsletterTemplate.d.ts.map +1 -0
  114. package/dist/templates/WelcomeTemplate.d.ts +55 -0
  115. package/dist/templates/WelcomeTemplate.d.ts.map +1 -0
  116. package/dist/templates/index.d.ts +7 -0
  117. package/dist/templates/index.d.ts.map +1 -0
  118. package/dist/types/index.d.ts +332 -0
  119. package/dist/types/index.d.ts.map +1 -0
  120. package/dist/utils/jwt.d.ts +32 -0
  121. package/dist/utils/jwt.d.ts.map +1 -0
  122. package/dist/utils/validation.d.ts +25 -0
  123. package/dist/utils/validation.d.ts.map +1 -0
  124. package/package.json +128 -0
package/README.md ADDED
@@ -0,0 +1,430 @@
1
+ # Payload Newsletter Plugin
2
+
3
+ A complete newsletter management plugin for Payload CMS that provides subscriber management, magic link authentication, and email service integration out of the box.
4
+
5
+ ## Features
6
+
7
+ - 📧 **Complete Subscriber Management** - Ready-to-use subscriber collection with all essential fields
8
+ - 🔐 **Magic Link Authentication** - Passwordless authentication for subscribers (separate from Payload auth)
9
+ - 📨 **Email Service Integration** - Built-in support for Resend and Broadcast
10
+ - 📅 **Newsletter Scheduling** - Schedule newsletters from your articles collection
11
+ - ⚛️ **React Components** - Pre-built signup forms and preference management UI
12
+ - 🌍 **Internationalization** - Multi-language support built-in
13
+ - 📊 **Analytics Ready** - UTM tracking and signup metadata collection
14
+ - ⚙️ **Admin UI Configuration** - Manage email settings through Payload admin panel
15
+
16
+ ## Quick Start
17
+
18
+ ### 1. Install the plugin
19
+
20
+ **Note: This plugin is not yet published to npm. Install directly from GitHub:**
21
+
22
+ ```bash
23
+ bun add github:aniketpanjwani/payload-plugin-email-newsletter
24
+ # or
25
+ npm install github:aniketpanjwani/payload-plugin-email-newsletter
26
+ # or
27
+ yarn add github:aniketpanjwani/payload-plugin-email-newsletter
28
+ # or
29
+ pnpm add github:aniketpanjwani/payload-plugin-email-newsletter
30
+ ```
31
+
32
+ Once published to npm, you'll be able to install with:
33
+ ```bash
34
+ bun add payload-plugin-newsletter
35
+ # or
36
+ npm install payload-plugin-newsletter
37
+ ```
38
+
39
+ ### 2. Add to your Payload config
40
+
41
+ ```typescript
42
+ import { buildConfig } from 'payload/config'
43
+ import { newsletterPlugin } from 'payload-plugin-newsletter'
44
+
45
+ export default buildConfig({
46
+ plugins: [
47
+ newsletterPlugin({
48
+ // Choose your email provider
49
+ providers: {
50
+ default: 'resend', // or 'broadcast'
51
+ resend: {
52
+ apiKey: process.env.RESEND_API_KEY,
53
+ fromAddress: 'hello@yoursite.com',
54
+ fromName: 'Your Newsletter',
55
+ audienceIds: {
56
+ en: {
57
+ production: 'your_audience_id',
58
+ development: 'your_dev_audience_id',
59
+ },
60
+ },
61
+ },
62
+ },
63
+ }),
64
+ ],
65
+ // ... rest of your config
66
+ })
67
+ ```
68
+
69
+ ### 3. That's it! 🎉
70
+
71
+ The plugin automatically adds:
72
+ - A `subscribers` collection to manage your subscribers
73
+ - A `newsletter-settings` global for email configuration
74
+ - API endpoints for subscription and authentication
75
+ - Newsletter scheduling fields to your articles (optional)
76
+
77
+ ## Basic Usage
78
+
79
+ ### Frontend Integration
80
+
81
+ #### Simple Newsletter Signup Form
82
+
83
+ ```tsx
84
+ import { NewsletterForm } from 'payload-plugin-newsletter/components'
85
+
86
+ export function MyHomepage() {
87
+ return (
88
+ <NewsletterForm
89
+ onSuccess={() => console.log('Subscribed!')}
90
+ onError={(error) => console.error(error)}
91
+ />
92
+ )
93
+ }
94
+ ```
95
+
96
+ #### Custom Signup Form
97
+
98
+ ```tsx
99
+ async function handleSubscribe(email: string) {
100
+ const response = await fetch('/api/newsletter/subscribe', {
101
+ method: 'POST',
102
+ headers: { 'Content-Type': 'application/json' },
103
+ body: JSON.stringify({ email }),
104
+ })
105
+
106
+ if (!response.ok) {
107
+ throw new Error('Subscription failed')
108
+ }
109
+
110
+ return response.json()
111
+ }
112
+ ```
113
+
114
+ ### Managing Subscribers
115
+
116
+ Subscribers can be managed through the Payload admin panel at `/admin/collections/subscribers`.
117
+
118
+ ### Email Settings
119
+
120
+ After setup, configure email settings at `/admin/globals/newsletter-settings` in your admin panel. You can:
121
+ - Switch between email providers
122
+ - Update API keys and settings
123
+ - Customize email templates
124
+ - Set subscription preferences
125
+
126
+ ## Configuration Options
127
+
128
+ ### Minimal Configuration
129
+
130
+ ```typescript
131
+ newsletterPlugin({
132
+ providers: {
133
+ default: 'resend',
134
+ resend: {
135
+ apiKey: process.env.RESEND_API_KEY,
136
+ fromAddress: 'newsletter@yoursite.com',
137
+ fromName: 'Your Newsletter',
138
+ },
139
+ },
140
+ })
141
+ ```
142
+
143
+ ### Full Configuration
144
+
145
+ ```typescript
146
+ newsletterPlugin({
147
+ // Subscriber collection slug (default: 'subscribers')
148
+ subscribersSlug: 'newsletter-subscribers',
149
+
150
+ // Email providers
151
+ providers: {
152
+ default: 'resend',
153
+ resend: {
154
+ apiKey: process.env.RESEND_API_KEY,
155
+ fromAddress: 'newsletter@yoursite.com',
156
+ fromName: 'Your Newsletter',
157
+ audienceIds: {
158
+ en: {
159
+ production: 'aud_prod_123',
160
+ development: 'aud_dev_123',
161
+ },
162
+ es: {
163
+ production: 'aud_prod_456',
164
+ development: 'aud_dev_456',
165
+ },
166
+ },
167
+ },
168
+ },
169
+
170
+ // Magic link authentication
171
+ auth: {
172
+ enabled: true,
173
+ tokenExpiration: '7d', // How long magic links are valid
174
+ magicLinkPath: '/newsletter/verify', // Where to redirect for verification
175
+ },
176
+
177
+ // Features
178
+ features: {
179
+ // Lead magnets (e.g., downloadable PDFs)
180
+ leadMagnets: {
181
+ enabled: true,
182
+ collection: 'media', // Which collection stores your lead magnets
183
+ },
184
+
185
+ // Post-signup surveys
186
+ surveys: {
187
+ enabled: true,
188
+ questions: [
189
+ {
190
+ id: 'interests',
191
+ question: 'What topics interest you?',
192
+ type: 'multiselect',
193
+ options: ['Tech', 'Business', 'Design'],
194
+ },
195
+ ],
196
+ },
197
+
198
+ // Newsletter scheduling for articles
199
+ newsletterScheduling: {
200
+ enabled: true,
201
+ articlesCollection: 'posts', // Your articles/posts collection
202
+ },
203
+
204
+ // UTM tracking
205
+ utmTracking: {
206
+ enabled: true,
207
+ fields: ['source', 'medium', 'campaign', 'content', 'term'],
208
+ },
209
+ },
210
+
211
+ // Internationalization
212
+ i18n: {
213
+ defaultLocale: 'en',
214
+ locales: ['en', 'es', 'fr'],
215
+ },
216
+
217
+ // Custom hooks
218
+ hooks: {
219
+ afterSubscribe: async ({ doc, req }) => {
220
+ // Send to analytics, CRM, etc.
221
+ console.log('New subscriber:', doc.email)
222
+ },
223
+ },
224
+ })
225
+ ```
226
+
227
+ ## API Endpoints
228
+
229
+ The plugin adds these endpoints to your application:
230
+
231
+ ### POST `/api/newsletter/subscribe`
232
+ Subscribe a new email address
233
+
234
+ ```typescript
235
+ // Request
236
+ {
237
+ "email": "user@example.com",
238
+ "name": "John Doe", // optional
239
+ "preferences": { // optional
240
+ "newsletter": true,
241
+ "announcements": false
242
+ }
243
+ }
244
+
245
+ // Response
246
+ {
247
+ "success": true,
248
+ "subscriber": { /* subscriber object */ }
249
+ }
250
+ ```
251
+
252
+ ### POST `/api/newsletter/verify-magic-link`
253
+ Verify a magic link token
254
+
255
+ ```typescript
256
+ // Request
257
+ {
258
+ "token": "eyJhbGc..."
259
+ }
260
+
261
+ // Response
262
+ {
263
+ "success": true,
264
+ "subscriber": { /* subscriber object */ },
265
+ "sessionToken": "eyJhbGc..."
266
+ }
267
+ ```
268
+
269
+ ### GET/POST `/api/newsletter/preferences`
270
+ Get or update subscriber preferences (requires magic link auth)
271
+
272
+ ### POST `/api/newsletter/unsubscribe`
273
+ Unsubscribe an email address
274
+
275
+ ## Newsletter Scheduling
276
+
277
+ If you enable newsletter scheduling, the plugin adds scheduling fields to your articles collection:
278
+
279
+ ```typescript
280
+ features: {
281
+ newsletterScheduling: {
282
+ enabled: true,
283
+ articlesCollection: 'articles', // Your existing collection
284
+ }
285
+ }
286
+ ```
287
+
288
+ This adds a "Newsletter Scheduling" group to your articles with:
289
+ - Schedule toggle
290
+ - Send date/time picker
291
+ - Audience segment selection
292
+ - Send status tracking
293
+
294
+ ## Email Providers
295
+
296
+ ### Resend
297
+
298
+ [Resend](https://resend.com) is a modern email API for developers.
299
+
300
+ ```typescript
301
+ providers: {
302
+ default: 'resend',
303
+ resend: {
304
+ apiKey: process.env.RESEND_API_KEY,
305
+ fromAddress: 'hello@yoursite.com',
306
+ fromName: 'Your Newsletter',
307
+ audienceIds: {
308
+ en: {
309
+ production: 'your_audience_id',
310
+ },
311
+ },
312
+ },
313
+ }
314
+ ```
315
+
316
+ ### Broadcast
317
+
318
+ [Broadcast](https://github.com/socketry/broadcast) is a self-hosted email automation platform.
319
+
320
+ ```typescript
321
+ providers: {
322
+ default: 'broadcast',
323
+ broadcast: {
324
+ apiUrl: 'https://broadcast.yoursite.com',
325
+ tokens: {
326
+ production: process.env.BROADCAST_TOKEN,
327
+ development: process.env.BROADCAST_DEV_TOKEN,
328
+ },
329
+ fromAddress: 'hello@yoursite.com',
330
+ fromName: 'Your Newsletter',
331
+ },
332
+ }
333
+ ```
334
+
335
+ ## TypeScript
336
+
337
+ The plugin is fully typed. Import types as needed:
338
+
339
+ ```typescript
340
+ import type {
341
+ NewsletterPluginConfig,
342
+ Subscriber,
343
+ EmailProvider
344
+ } from 'payload-plugin-newsletter/types'
345
+ ```
346
+
347
+ ## Customization
348
+
349
+ ### Custom Fields
350
+
351
+ Add custom fields to the subscribers collection:
352
+
353
+ ```typescript
354
+ newsletterPlugin({
355
+ fields: {
356
+ additional: [
357
+ {
358
+ name: 'company',
359
+ type: 'text',
360
+ label: 'Company Name',
361
+ },
362
+ {
363
+ name: 'role',
364
+ type: 'select',
365
+ options: ['developer', 'designer', 'manager'],
366
+ },
367
+ ],
368
+ },
369
+ })
370
+ ```
371
+
372
+ ### Custom Email Templates
373
+
374
+ Override the default email templates:
375
+
376
+ ```typescript
377
+ import { WelcomeEmail } from './emails/Welcome'
378
+
379
+ newsletterPlugin({
380
+ templates: {
381
+ welcome: WelcomeEmail,
382
+ },
383
+ })
384
+ ```
385
+
386
+ ## Troubleshooting
387
+
388
+ ### Common Issues
389
+
390
+ **"Already subscribed" error**
391
+ - The email already exists in the subscribers collection
392
+ - Check the admin panel to manage existing subscribers
393
+
394
+ **Magic links not working**
395
+ - Ensure `JWT_SECRET` is set in your environment variables
396
+ - Check that the `magicLinkPath` matches your frontend route
397
+
398
+ **Emails not sending**
399
+ - Verify your API keys are correct
400
+ - Check the email provider's dashboard for errors
401
+ - Ensure from address is verified with your provider
402
+
403
+ ## Migration Guide
404
+
405
+ Coming from another newsletter system? The plugin stores subscribers in a standard Payload collection, making it easy to import existing data:
406
+
407
+ ```typescript
408
+ // Example migration script
409
+ const existingSubscribers = await getFromOldSystem()
410
+
411
+ for (const subscriber of existingSubscribers) {
412
+ await payload.create({
413
+ collection: 'subscribers',
414
+ data: {
415
+ email: subscriber.email,
416
+ name: subscriber.name,
417
+ subscriptionStatus: 'active',
418
+ // Map other fields as needed
419
+ },
420
+ })
421
+ }
422
+ ```
423
+
424
+ ## Contributing
425
+
426
+ We welcome contributions! Please see our [feedback and contribution guide](./FEEDBACK.md).
427
+
428
+ ## License
429
+
430
+ MIT