@cakemail-org/cakemail-cli 1.5.0 → 2.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.
Files changed (234) hide show
  1. package/.claude/settings.local.json +12 -0
  2. package/.env.example +40 -0
  3. package/.env.test.example +45 -0
  4. package/CHANGELOG.md +1031 -0
  5. package/README.md +319 -15
  6. package/audit-formats.js +128 -0
  7. package/cakemail.rb +20 -0
  8. package/dist/cli.js +27 -10
  9. package/dist/cli.js.map +1 -1
  10. package/dist/client.d.ts +2 -0
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js +16 -6
  13. package/dist/client.js.map +1 -1
  14. package/dist/commands/account.js +1 -1
  15. package/dist/commands/account.js.map +1 -1
  16. package/dist/commands/attributes.js +1 -1
  17. package/dist/commands/attributes.js.map +1 -1
  18. package/dist/commands/campaigns.d.ts.map +1 -1
  19. package/dist/commands/campaigns.js +103 -8
  20. package/dist/commands/campaigns.js.map +1 -1
  21. package/dist/commands/config.d.ts.map +1 -1
  22. package/dist/commands/config.js +63 -4
  23. package/dist/commands/config.js.map +1 -1
  24. package/dist/commands/contacts.d.ts.map +1 -1
  25. package/dist/commands/contacts.js +91 -12
  26. package/dist/commands/contacts.js.map +1 -1
  27. package/dist/commands/emails.js +1 -1
  28. package/dist/commands/emails.js.map +1 -1
  29. package/dist/commands/interests.d.ts +5 -0
  30. package/dist/commands/interests.d.ts.map +1 -0
  31. package/dist/commands/interests.js +172 -0
  32. package/dist/commands/interests.js.map +1 -0
  33. package/dist/commands/lists.d.ts.map +1 -1
  34. package/dist/commands/lists.js +6 -8
  35. package/dist/commands/lists.js.map +1 -1
  36. package/dist/commands/logs.d.ts +5 -0
  37. package/dist/commands/logs.d.ts.map +1 -0
  38. package/dist/commands/logs.js +237 -0
  39. package/dist/commands/logs.js.map +1 -0
  40. package/dist/commands/reports.js +1 -1
  41. package/dist/commands/reports.js.map +1 -1
  42. package/dist/commands/segments.js +1 -1
  43. package/dist/commands/segments.js.map +1 -1
  44. package/dist/commands/senders.d.ts.map +1 -1
  45. package/dist/commands/senders.js +11 -8
  46. package/dist/commands/senders.js.map +1 -1
  47. package/dist/commands/suppressed.js +1 -1
  48. package/dist/commands/suppressed.js.map +1 -1
  49. package/dist/commands/tags.d.ts +5 -0
  50. package/dist/commands/tags.d.ts.map +1 -0
  51. package/dist/commands/tags.js +124 -0
  52. package/dist/commands/tags.js.map +1 -0
  53. package/dist/commands/templates.js +1 -1
  54. package/dist/commands/templates.js.map +1 -1
  55. package/dist/commands/transactional-templates.d.ts +5 -0
  56. package/dist/commands/transactional-templates.d.ts.map +1 -0
  57. package/dist/commands/transactional-templates.js +354 -0
  58. package/dist/commands/transactional-templates.js.map +1 -0
  59. package/dist/commands/webhooks.js +1 -1
  60. package/dist/commands/webhooks.js.map +1 -1
  61. package/dist/utils/auth.d.ts +8 -1
  62. package/dist/utils/auth.d.ts.map +1 -1
  63. package/dist/utils/auth.js +39 -11
  64. package/dist/utils/auth.js.map +1 -1
  65. package/dist/utils/config-file.d.ts +7 -0
  66. package/dist/utils/config-file.d.ts.map +1 -1
  67. package/dist/utils/config-file.js +15 -0
  68. package/dist/utils/config-file.js.map +1 -1
  69. package/dist/utils/config.d.ts +2 -0
  70. package/dist/utils/config.d.ts.map +1 -1
  71. package/dist/utils/config.js +12 -4
  72. package/dist/utils/config.js.map +1 -1
  73. package/dist/utils/errors.js +1 -1
  74. package/dist/utils/errors.js.map +1 -1
  75. package/dist/utils/list-defaults.d.ts +33 -0
  76. package/dist/utils/list-defaults.d.ts.map +1 -0
  77. package/dist/utils/list-defaults.js +52 -0
  78. package/dist/utils/list-defaults.js.map +1 -0
  79. package/dist/utils/output.d.ts.map +1 -1
  80. package/dist/utils/output.js +36 -13
  81. package/dist/utils/output.js.map +1 -1
  82. package/dist/utils/progress.d.ts.map +1 -1
  83. package/dist/utils/progress.js +32 -4
  84. package/dist/utils/progress.js.map +1 -1
  85. package/dist/utils/spinner.d.ts +17 -0
  86. package/dist/utils/spinner.d.ts.map +1 -0
  87. package/dist/utils/spinner.js +43 -0
  88. package/dist/utils/spinner.js.map +1 -0
  89. package/docs/DOCUMENTATION-STANDARD.md +1068 -0
  90. package/docs/README.md +161 -0
  91. package/docs/developer/ARCHITECTURE.md +516 -0
  92. package/docs/developer/AUTH.md +204 -0
  93. package/docs/developer/CONTRIBUTING.md +227 -0
  94. package/docs/developer/DOCUMENTATION_SUMMARY.md +346 -0
  95. package/docs/developer/PROJECT_INDEX.md +365 -0
  96. package/docs/planning/API_COVERAGE.md +1045 -0
  97. package/docs/planning/BACKLOG.md +1159 -0
  98. package/docs/planning/PROFILE_SYSTEM_TASKS.md +287 -0
  99. package/docs/planning/UX_IMPLEMENTATION_PLAN.md +691 -0
  100. package/docs/planning/archive/RELEASE_CHECKLIST_v1.3.0.md +332 -0
  101. package/docs/planning/archive/RELEASE_v1.3.0.md +428 -0
  102. package/docs/planning/archive/cakemail-cli-ux-improvements.md +438 -0
  103. package/docs/planning/cakemail-profile-system-plan.md +1121 -0
  104. package/docs/testing/AI_USER_SIMULATION_DESIGN.md +1342 -0
  105. package/docs/testing/KENOGAMI_BIDIRECTIONAL_FLOW.md +1517 -0
  106. package/docs/testing/KENOGAMI_TRUTH_RECONCILIATION_SYSTEM.md +1369 -0
  107. package/docs/user-manual/.obsidian/app.json +1 -0
  108. package/docs/user-manual/.obsidian/appearance.json +1 -0
  109. package/docs/user-manual/.obsidian/core-plugins.json +33 -0
  110. package/docs/user-manual/.obsidian/workspace.json +167 -0
  111. package/docs/user-manual/01-getting-started/01-installation.md +214 -0
  112. package/docs/user-manual/01-getting-started/02-quick-start.md +432 -0
  113. package/docs/user-manual/01-getting-started/03-authentication.md +448 -0
  114. package/docs/user-manual/01-getting-started/04-configuration.md +430 -0
  115. package/docs/user-manual/01-getting-started/05-output-formats.md +447 -0
  116. package/docs/user-manual/02-core-concepts/01-accounts.md +514 -0
  117. package/docs/user-manual/02-core-concepts/02-profile-system.md +771 -0
  118. package/docs/user-manual/02-core-concepts/03-smart-defaults.md +485 -0
  119. package/docs/user-manual/02-core-concepts/04-authentication-methods.md +435 -0
  120. package/docs/user-manual/02-core-concepts/05-pagination-filtering.md +600 -0
  121. package/docs/user-manual/02-core-concepts/06-error-handling.md +718 -0
  122. package/docs/user-manual/02-core-concepts/07-api-coverage.md +483 -0
  123. package/docs/user-manual/03-email-operations/01-senders.md +490 -0
  124. package/docs/user-manual/03-email-operations/02-templates.md +444 -0
  125. package/docs/user-manual/03-email-operations/03-transactional-emails.md +706 -0
  126. package/docs/user-manual/03-email-operations/04-email-tracking.md +407 -0
  127. package/docs/user-manual/04-campaign-management/01-campaigns-basics.md +394 -0
  128. package/docs/user-manual/04-campaign-management/02-campaign-scheduling.md +630 -0
  129. package/docs/user-manual/04-campaign-management/03-campaign-testing.md +997 -0
  130. package/docs/user-manual/04-campaign-management/04-campaign-lifecycle.md +709 -0
  131. package/docs/user-manual/04-campaign-management/05-campaign-links.md +934 -0
  132. package/docs/user-manual/05-contact-management/01-lists.md +836 -0
  133. package/docs/user-manual/05-contact-management/02-contacts.md +1035 -0
  134. package/docs/user-manual/05-contact-management/03-custom-attributes.md +788 -0
  135. package/docs/user-manual/05-contact-management/04-segments.md +1028 -0
  136. package/docs/user-manual/05-contact-management/05-contact-import-export.md +1031 -0
  137. package/docs/user-manual/06-analytics-reporting/01-campaign-analytics.md +867 -0
  138. package/docs/user-manual/06-analytics-reporting/02-account-reports.md +227 -0
  139. package/docs/user-manual/07-integrations/01-webhooks-integration.md +259 -0
  140. package/docs/user-manual/07-integrations/02-automation.md +326 -0
  141. package/docs/user-manual/08-advanced-usage/01-scripting-patterns.md +672 -0
  142. package/docs/user-manual/08-advanced-usage/02-bulk-operations.md +932 -0
  143. package/docs/user-manual/08-advanced-usage/03-ci-cd-integration.md +892 -0
  144. package/docs/user-manual/08-advanced-usage/04-performance-optimization.md +766 -0
  145. package/docs/user-manual/09-command-reference/01-config.md +776 -0
  146. package/docs/user-manual/09-command-reference/02-account.md +652 -0
  147. package/docs/user-manual/09-command-reference/03-lists.md +958 -0
  148. package/docs/user-manual/09-command-reference/04-contacts.md +1408 -0
  149. package/docs/user-manual/09-command-reference/05-attributes.md +617 -0
  150. package/docs/user-manual/09-command-reference/06-segments.md +894 -0
  151. package/docs/user-manual/09-command-reference/07-senders.md +803 -0
  152. package/docs/user-manual/09-command-reference/08-templates.md +818 -0
  153. package/docs/user-manual/09-command-reference/09-campaigns.md +1250 -0
  154. package/docs/user-manual/09-command-reference/10-emails.md +807 -0
  155. package/docs/user-manual/09-command-reference/11-reports.md +1135 -0
  156. package/docs/user-manual/09-command-reference/12-webhooks.md +773 -0
  157. package/docs/user-manual/09-command-reference/13-suppressed.md +797 -0
  158. package/docs/user-manual/09-command-reference/14-interests.md +630 -0
  159. package/docs/user-manual/09-command-reference/15-tags.md +584 -0
  160. package/docs/user-manual/09-command-reference/16-logs.md +656 -0
  161. package/docs/user-manual/09-command-reference/17-transactional-templates.md +850 -0
  162. package/docs/user-manual/10-troubleshooting/01-common-errors.md +457 -0
  163. package/docs/user-manual/10-troubleshooting/02-authentication-issues.md +558 -0
  164. package/docs/user-manual/10-troubleshooting/03-connection-problems.md +634 -0
  165. package/docs/user-manual/10-troubleshooting/04-debugging.md +725 -0
  166. package/docs/user-manual/11-appendix/04-faq.md +484 -0
  167. package/docs/user-manual/11-appendix/05-glossary.md +250 -0
  168. package/docs/user-manual/README.md +0 -0
  169. package/package.json +13 -47
  170. package/src/cli.ts +125 -0
  171. package/src/client.ts +16 -0
  172. package/src/commands/account.ts +267 -0
  173. package/src/commands/accounts.ts +78 -0
  174. package/src/commands/actions.ts +249 -0
  175. package/src/commands/attributes.ts +139 -0
  176. package/src/commands/campaign-blueprints.ts +106 -0
  177. package/src/commands/campaigns.ts +469 -0
  178. package/src/commands/config.ts +77 -0
  179. package/src/commands/contacts.ts +612 -0
  180. package/src/commands/custom-attributes.ts +127 -0
  181. package/src/commands/dkims.ts +117 -0
  182. package/src/commands/domains.ts +82 -0
  183. package/src/commands/email-apis.ts +569 -0
  184. package/src/commands/emails.ts +197 -0
  185. package/src/commands/forms.ts +283 -0
  186. package/src/commands/interests.ts +155 -0
  187. package/src/commands/links.ts +38 -0
  188. package/src/commands/lists.ts +406 -0
  189. package/src/commands/logos.ts +71 -0
  190. package/src/commands/logs.ts +386 -0
  191. package/src/commands/reports.ts +306 -0
  192. package/src/commands/segments.ts +158 -0
  193. package/src/commands/senders.ts +204 -0
  194. package/src/commands/sub-accounts.ts +271 -0
  195. package/src/commands/suppressed-emails.ts +234 -0
  196. package/src/commands/suppressed.ts +198 -0
  197. package/src/commands/system-emails.ts +85 -0
  198. package/src/commands/tags.ts +146 -0
  199. package/src/commands/tasks.ts +116 -0
  200. package/src/commands/templates.ts +189 -0
  201. package/src/commands/tokens.ts +83 -0
  202. package/src/commands/transactional-emails.ts +374 -0
  203. package/src/commands/transactional-templates.ts +385 -0
  204. package/src/commands/users.ts +506 -0
  205. package/src/commands/webhooks.ts +172 -0
  206. package/src/commands/workflow-blueprints.ts +123 -0
  207. package/src/commands/workflows.ts +265 -0
  208. package/src/types/profile.ts +93 -0
  209. package/src/utils/auth.ts +272 -0
  210. package/src/utils/config-file.ts +96 -0
  211. package/src/utils/config.ts +134 -0
  212. package/src/utils/confirm.ts +32 -0
  213. package/src/utils/defaults.ts +99 -0
  214. package/src/utils/errors.ts +116 -0
  215. package/src/utils/interactive.ts +91 -0
  216. package/src/utils/list-defaults.ts +74 -0
  217. package/src/utils/output.ts +190 -0
  218. package/src/utils/progress.ts +320 -0
  219. package/src/utils/spinner.ts +22 -0
  220. package/tests/IMPLEMENTATION_STATUS.md +258 -0
  221. package/tests/PTY_SETUP.md +118 -0
  222. package/tests/PTY_TESTING_GUIDE.md +507 -0
  223. package/tests/README.md +244 -0
  224. package/tests/fixtures/api-responses/campaigns.json +34 -0
  225. package/tests/fixtures/test-config.json +13 -0
  226. package/tests/helpers/cli-runner.ts +128 -0
  227. package/tests/helpers/mock-server.ts +301 -0
  228. package/tests/helpers/pty-runner.ts +181 -0
  229. package/tests/integration/campaigns-real-api.test.ts +196 -0
  230. package/tests/integration/setup-integration.ts +50 -0
  231. package/tests/pty/campaigns.test.ts +241 -0
  232. package/tests/setup.ts +34 -0
  233. package/tsconfig.json +15 -0
  234. package/vitest.config.ts +28 -0
@@ -0,0 +1,892 @@
1
+ # CI/CD Integration
2
+
3
+ Integrate Cakemail CLI into continuous integration and deployment pipelines for automated email marketing workflows.
4
+
5
+ ## Overview
6
+
7
+ Learn to:
8
+ - Integrate with GitHub Actions
9
+ - Configure GitLab CI pipelines
10
+ - Set up Jenkins jobs
11
+ - Use Docker containers
12
+ - Implement deployment strategies
13
+ - Handle secrets securely
14
+ - Test campaigns automatically
15
+
16
+ ## GitHub Actions
17
+
18
+ ### Basic Campaign Deployment
19
+
20
+ ```yaml
21
+ # .github/workflows/deploy-campaign.yml
22
+ name: Deploy Email Campaign
23
+
24
+ on:
25
+ push:
26
+ branches: [main]
27
+ paths:
28
+ - 'campaigns/**'
29
+ - '.github/workflows/deploy-campaign.yml'
30
+
31
+ env:
32
+ LIST_ID: 123
33
+ SENDER_ID: 101
34
+
35
+ jobs:
36
+ deploy:
37
+ runs-on: ubuntu-latest
38
+
39
+ steps:
40
+ - name: Checkout code
41
+ uses: actions/checkout@v3
42
+
43
+ - name: Setup Node.js
44
+ uses: actions/setup-node@v3
45
+ with:
46
+ node-version: '18'
47
+
48
+ - name: Install Cakemail CLI
49
+ run: npm install -g @cakemail-org/cakemail-cli
50
+
51
+ - name: Configure Cakemail
52
+ env:
53
+ CAKEMAIL_EMAIL: ${{ secrets.CAKEMAIL_EMAIL }}
54
+ CAKEMAIL_PASSWORD: ${{ secrets.CAKEMAIL_PASSWORD }}
55
+ run: |
56
+ echo "CAKEMAIL_EMAIL=$CAKEMAIL_EMAIL" > .env
57
+ echo "CAKEMAIL_PASSWORD=$CAKEMAIL_PASSWORD" >> .env
58
+
59
+ - name: Validate HTML
60
+ run: |
61
+ npm install -g html-validator-cli
62
+ html-validator campaigns/*.html
63
+
64
+ - name: Create campaign
65
+ id: create
66
+ run: |
67
+ CAMPAIGN_ID=$(cakemail campaigns create \
68
+ -n "Campaign $(date +%Y-%m-%d)" \
69
+ -l ${{ env.LIST_ID }} \
70
+ -s ${{ env.SENDER_ID }} \
71
+ --html-file campaigns/newsletter.html \
72
+ --subject "$(cat campaigns/subject.txt)" \
73
+ -f json | jq -r '.id')
74
+ echo "campaign_id=$CAMPAIGN_ID" >> $GITHUB_OUTPUT
75
+ echo "Created campaign: $CAMPAIGN_ID"
76
+
77
+ - name: Send test email
78
+ run: |
79
+ cakemail campaigns test ${{ steps.create.outputs.campaign_id }} \
80
+ -e ${{ secrets.TEST_EMAIL }}
81
+
82
+ - name: Schedule campaign
83
+ if: github.ref == 'refs/heads/main'
84
+ run: |
85
+ cakemail campaigns schedule ${{ steps.create.outputs.campaign_id }} \
86
+ --when "$(date -d 'tomorrow 09:00' '+%Y-%m-%d %H:%M:%S')"
87
+
88
+ - name: Comment on commit
89
+ uses: actions/github-script@v6
90
+ with:
91
+ script: |
92
+ github.rest.repos.createCommitComment({
93
+ owner: context.repo.owner,
94
+ repo: context.repo.repo,
95
+ commit_sha: context.sha,
96
+ body: '✅ Campaign ${{ steps.create.outputs.campaign_id }} deployed successfully'
97
+ })
98
+ ```
99
+
100
+ ### Multi-Environment Deployment
101
+
102
+ ```yaml
103
+ # .github/workflows/multi-env-deploy.yml
104
+ name: Multi-Environment Deploy
105
+
106
+ on:
107
+ push:
108
+ branches: [develop, staging, main]
109
+
110
+ jobs:
111
+ deploy:
112
+ runs-on: ubuntu-latest
113
+ strategy:
114
+ matrix:
115
+ include:
116
+ - branch: develop
117
+ environment: development
118
+ list_id: 123
119
+ sender_id: 101
120
+ auto_send: false
121
+ - branch: staging
122
+ environment: staging
123
+ list_id: 124
124
+ sender_id: 102
125
+ auto_send: false
126
+ - branch: main
127
+ environment: production
128
+ list_id: 125
129
+ sender_id: 103
130
+ auto_send: true
131
+
132
+ steps:
133
+ - uses: actions/checkout@v3
134
+
135
+ - name: Setup environment
136
+ if: github.ref == format('refs/heads/{0}', matrix.branch)
137
+ run: |
138
+ echo "ENVIRONMENT=${{ matrix.environment }}" >> $GITHUB_ENV
139
+ echo "LIST_ID=${{ matrix.list_id }}" >> $GITHUB_ENV
140
+ echo "SENDER_ID=${{ matrix.sender_id }}" >> $GITHUB_ENV
141
+
142
+ - name: Install CLI
143
+ if: github.ref == format('refs/heads/{0}', matrix.branch)
144
+ run: npm install -g @cakemail-org/cakemail-cli
145
+
146
+ - name: Configure Cakemail
147
+ if: github.ref == format('refs/heads/{0}', matrix.branch)
148
+ env:
149
+ CAKEMAIL_EMAIL: ${{ secrets[format('CAKEMAIL_EMAIL_{0}', matrix.environment)] }}
150
+ CAKEMAIL_PASSWORD: ${{ secrets[format('CAKEMAIL_PASSWORD_{0}', matrix.environment)] }}
151
+ run: |
152
+ echo "CAKEMAIL_EMAIL=$CAKEMAIL_EMAIL" > .env
153
+ echo "CAKEMAIL_PASSWORD=$CAKEMAIL_PASSWORD" >> .env
154
+
155
+ - name: Deploy campaign
156
+ if: github.ref == format('refs/heads/{0}', matrix.branch)
157
+ run: |
158
+ echo "Deploying to ${{ matrix.environment }}"
159
+ CAMPAIGN_ID=$(cakemail campaigns create \
160
+ -n "[${{ matrix.environment }}] Newsletter" \
161
+ -l ${{ matrix.list_id }} \
162
+ -s ${{ matrix.sender_id }} \
163
+ --html-file campaigns/newsletter.html \
164
+ -f json | jq -r '.id')
165
+
166
+ if [ "${{ matrix.auto_send }}" = "true" ]; then
167
+ cakemail campaigns schedule "$CAMPAIGN_ID"
168
+ else
169
+ echo "Campaign created but not scheduled (manual approval required)"
170
+ fi
171
+ ```
172
+
173
+ ### Scheduled Campaign Workflow
174
+
175
+ ```yaml
176
+ # .github/workflows/scheduled-newsletter.yml
177
+ name: Scheduled Newsletter
178
+
179
+ on:
180
+ schedule:
181
+ # Run every Monday at 8 AM UTC
182
+ - cron: '0 8 * * 1'
183
+ workflow_dispatch: # Allow manual trigger
184
+
185
+ jobs:
186
+ send-newsletter:
187
+ runs-on: ubuntu-latest
188
+
189
+ steps:
190
+ - uses: actions/checkout@v3
191
+
192
+ - name: Install CLI
193
+ run: npm install -g @cakemail-org/cakemail-cli
194
+
195
+ - name: Configure
196
+ env:
197
+ CAKEMAIL_EMAIL: ${{ secrets.CAKEMAIL_EMAIL }}
198
+ CAKEMAIL_PASSWORD: ${{ secrets.CAKEMAIL_PASSWORD }}
199
+ run: |
200
+ echo "CAKEMAIL_EMAIL=$CAKEMAIL_EMAIL" > .env
201
+ echo "CAKEMAIL_PASSWORD=$CAKEMAIL_PASSWORD" >> .env
202
+
203
+ - name: Generate content
204
+ run: |
205
+ # Generate dynamic content (example)
206
+ ./scripts/generate-newsletter-content.sh > campaigns/weekly-newsletter.html
207
+
208
+ - name: Create and send
209
+ run: |
210
+ CAMPAIGN_ID=$(cakemail campaigns create \
211
+ -n "Weekly Newsletter $(date +%Y-%m-%d)" \
212
+ -l 123 \
213
+ -s 101 \
214
+ --html-file campaigns/weekly-newsletter.html \
215
+ --subject "This Week's Top Stories" \
216
+ -f json | jq -r '.id')
217
+
218
+ cakemail campaigns schedule "$CAMPAIGN_ID"
219
+ echo "Newsletter scheduled: $CAMPAIGN_ID"
220
+
221
+ - name: Notify Slack
222
+ if: always()
223
+ uses: slackapi/slack-github-action@v1
224
+ with:
225
+ payload: |
226
+ {
227
+ "text": "Weekly newsletter deployment: ${{ job.status }}"
228
+ }
229
+ env:
230
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
231
+ ```
232
+
233
+ ### Pull Request Preview
234
+
235
+ ```yaml
236
+ # .github/workflows/pr-preview.yml
237
+ name: Campaign Preview
238
+
239
+ on:
240
+ pull_request:
241
+ paths:
242
+ - 'campaigns/**'
243
+
244
+ jobs:
245
+ preview:
246
+ runs-on: ubuntu-latest
247
+
248
+ steps:
249
+ - uses: actions/checkout@v3
250
+
251
+ - name: Install CLI
252
+ run: npm install -g @cakemail-org/cakemail-cli
253
+
254
+ - name: Configure
255
+ env:
256
+ CAKEMAIL_EMAIL: ${{ secrets.CAKEMAIL_EMAIL }}
257
+ CAKEMAIL_PASSWORD: ${{ secrets.CAKEMAIL_PASSWORD }}
258
+ run: |
259
+ echo "CAKEMAIL_EMAIL=$CAKEMAIL_EMAIL" > .env
260
+ echo "CAKEMAIL_PASSWORD=$CAKEMAIL_PASSWORD" >> .env
261
+
262
+ - name: Create preview campaign
263
+ id: preview
264
+ run: |
265
+ CAMPAIGN_ID=$(cakemail campaigns create \
266
+ -n "[PREVIEW] PR #${{ github.event.pull_request.number }}" \
267
+ -l 123 \
268
+ -s 101 \
269
+ --html-file campaigns/newsletter.html \
270
+ --subject "[PREVIEW] ${{ github.event.pull_request.title }}" \
271
+ -f json | jq -r '.id')
272
+ echo "campaign_id=$CAMPAIGN_ID" >> $GITHUB_OUTPUT
273
+
274
+ - name: Send test email
275
+ run: |
276
+ cakemail campaigns test ${{ steps.preview.outputs.campaign_id }} \
277
+ -e ${{ github.event.pull_request.user.email }}
278
+
279
+ - name: Comment on PR
280
+ uses: actions/github-script@v6
281
+ with:
282
+ script: |
283
+ github.rest.issues.createComment({
284
+ issue_number: context.issue.number,
285
+ owner: context.repo.owner,
286
+ repo: context.repo.repo,
287
+ body: `## 📧 Campaign Preview\n\nPreview campaign created: **${{ steps.preview.outputs.campaign_id }}**\n\nTest email sent to: ${context.payload.pull_request.user.email}\n\n[View in Cakemail](https://app.cakemail.com/campaigns/${{ steps.preview.outputs.campaign_id }})`
288
+ })
289
+ ```
290
+
291
+ ## GitLab CI
292
+
293
+ ### Basic Pipeline
294
+
295
+ ```yaml
296
+ # .gitlab-ci.yml
297
+ stages:
298
+ - validate
299
+ - build
300
+ - deploy
301
+
302
+ variables:
303
+ LIST_ID: "123"
304
+ SENDER_ID: "101"
305
+
306
+ before_script:
307
+ - npm install -g @cakemail-org/cakemail-cli
308
+ - echo "CAKEMAIL_EMAIL=$CAKEMAIL_EMAIL" > .env
309
+ - echo "CAKEMAIL_PASSWORD=$CAKEMAIL_PASSWORD" >> .env
310
+
311
+ validate:
312
+ stage: validate
313
+ script:
314
+ - npm install -g html-validator-cli
315
+ - html-validator campaigns/*.html
316
+ - echo "HTML validation passed"
317
+ only:
318
+ - merge_requests
319
+ - main
320
+
321
+ test_campaign:
322
+ stage: build
323
+ script:
324
+ - |
325
+ CAMPAIGN_ID=$(cakemail campaigns create \
326
+ -n "[TEST] Campaign" \
327
+ -l $LIST_ID \
328
+ -s $SENDER_ID \
329
+ --html-file campaigns/newsletter.html \
330
+ -f json | jq -r '.id')
331
+ cakemail campaigns test $CAMPAIGN_ID -e test@company.com
332
+ echo "Test email sent for campaign $CAMPAIGN_ID"
333
+ only:
334
+ - merge_requests
335
+
336
+ deploy_production:
337
+ stage: deploy
338
+ script:
339
+ - |
340
+ CAMPAIGN_ID=$(cakemail campaigns create \
341
+ -n "Newsletter $(date +%Y-%m-%d)" \
342
+ -l $LIST_ID \
343
+ -s $SENDER_ID \
344
+ --html-file campaigns/newsletter.html \
345
+ --subject "$(cat campaigns/subject.txt)" \
346
+ -f json | jq -r '.id')
347
+ cakemail campaigns schedule $CAMPAIGN_ID --when "$(date -d 'tomorrow 09:00' '+%Y-%m-%d %H:%M:%S')"
348
+ echo "Campaign $CAMPAIGN_ID scheduled"
349
+ only:
350
+ - main
351
+ when: manual
352
+ ```
353
+
354
+ ### Multi-Stage Pipeline
355
+
356
+ ```yaml
357
+ # .gitlab-ci.yml
358
+ stages:
359
+ - test
360
+ - staging
361
+ - production
362
+
363
+ .deploy_template: &deploy_config
364
+ before_script:
365
+ - npm install -g @cakemail-org/cakemail-cli
366
+ - echo "CAKEMAIL_EMAIL=$CAKEMAIL_EMAIL" > .env
367
+ - echo "CAKEMAIL_PASSWORD=$CAKEMAIL_PASSWORD" >> .env
368
+ script:
369
+ - |
370
+ CAMPAIGN_ID=$(cakemail campaigns create \
371
+ -n "[$CI_ENVIRONMENT_NAME] Newsletter" \
372
+ -l $LIST_ID \
373
+ -s $SENDER_ID \
374
+ --html-file campaigns/newsletter.html \
375
+ -f json | jq -r '.id')
376
+ echo "Created campaign: $CAMPAIGN_ID"
377
+
378
+ if [ "$AUTO_SEND" = "true" ]; then
379
+ cakemail campaigns schedule $CAMPAIGN_ID
380
+ echo "Campaign scheduled"
381
+ fi
382
+
383
+ test:
384
+ <<: *deploy_config
385
+ stage: test
386
+ variables:
387
+ LIST_ID: "123"
388
+ SENDER_ID: "101"
389
+ AUTO_SEND: "false"
390
+ environment:
391
+ name: test
392
+ only:
393
+ - merge_requests
394
+
395
+ staging:
396
+ <<: *deploy_config
397
+ stage: staging
398
+ variables:
399
+ LIST_ID: "124"
400
+ SENDER_ID: "102"
401
+ AUTO_SEND: "false"
402
+ environment:
403
+ name: staging
404
+ only:
405
+ - develop
406
+
407
+ production:
408
+ <<: *deploy_config
409
+ stage: production
410
+ variables:
411
+ LIST_ID: "125"
412
+ SENDER_ID: "103"
413
+ AUTO_SEND: "true"
414
+ environment:
415
+ name: production
416
+ only:
417
+ - main
418
+ when: manual
419
+ ```
420
+
421
+ ## Jenkins
422
+
423
+ ### Declarative Pipeline
424
+
425
+ ```groovy
426
+ // Jenkinsfile
427
+ pipeline {
428
+ agent any
429
+
430
+ environment {
431
+ CAKEMAIL_EMAIL = credentials('cakemail-email')
432
+ CAKEMAIL_PASSWORD = credentials('cakemail-password')
433
+ LIST_ID = '123'
434
+ SENDER_ID = '101'
435
+ }
436
+
437
+ stages {
438
+ stage('Setup') {
439
+ steps {
440
+ sh 'npm install -g @cakemail-org/cakemail-cli'
441
+ sh '''
442
+ echo "CAKEMAIL_EMAIL=$CAKEMAIL_EMAIL" > .env
443
+ echo "CAKEMAIL_PASSWORD=$CAKEMAIL_PASSWORD" >> .env
444
+ '''
445
+ }
446
+ }
447
+
448
+ stage('Validate') {
449
+ steps {
450
+ sh 'npm install -g html-validator-cli'
451
+ sh 'html-validator campaigns/*.html'
452
+ }
453
+ }
454
+
455
+ stage('Create Campaign') {
456
+ steps {
457
+ script {
458
+ def campaignId = sh(
459
+ script: '''
460
+ cakemail campaigns create \
461
+ -n "Jenkins Campaign ${BUILD_NUMBER}" \
462
+ -l ${LIST_ID} \
463
+ -s ${SENDER_ID} \
464
+ --html-file campaigns/newsletter.html \
465
+ -f json | jq -r '.id'
466
+ ''',
467
+ returnStdout: true
468
+ ).trim()
469
+
470
+ env.CAMPAIGN_ID = campaignId
471
+ echo "Created campaign: ${campaignId}"
472
+ }
473
+ }
474
+ }
475
+
476
+ stage('Test') {
477
+ steps {
478
+ sh 'cakemail campaigns test ${CAMPAIGN_ID} -e test@company.com'
479
+ }
480
+ }
481
+
482
+ stage('Deploy') {
483
+ when {
484
+ branch 'main'
485
+ }
486
+ steps {
487
+ input message: 'Deploy campaign?', ok: 'Deploy'
488
+ sh 'cakemail campaigns schedule ${CAMPAIGN_ID}'
489
+ }
490
+ }
491
+ }
492
+
493
+ post {
494
+ success {
495
+ slackSend(
496
+ color: 'good',
497
+ message: "Campaign ${env.CAMPAIGN_ID} deployed successfully"
498
+ )
499
+ }
500
+ failure {
501
+ slackSend(
502
+ color: 'danger',
503
+ message: "Campaign deployment failed"
504
+ )
505
+ }
506
+ always {
507
+ cleanWs()
508
+ }
509
+ }
510
+ }
511
+ ```
512
+
513
+ ### Parameterized Build
514
+
515
+ ```groovy
516
+ // Jenkinsfile
517
+ pipeline {
518
+ agent any
519
+
520
+ parameters {
521
+ choice(
522
+ name: 'ENVIRONMENT',
523
+ choices: ['test', 'staging', 'production'],
524
+ description: 'Target environment'
525
+ )
526
+ string(
527
+ name: 'CAMPAIGN_NAME',
528
+ defaultValue: 'Newsletter',
529
+ description: 'Campaign name'
530
+ )
531
+ booleanParam(
532
+ name: 'AUTO_SCHEDULE',
533
+ defaultValue: false,
534
+ description: 'Automatically schedule campaign'
535
+ )
536
+ }
537
+
538
+ environment {
539
+ CAKEMAIL_EMAIL = credentials("cakemail-email-${params.ENVIRONMENT}")
540
+ CAKEMAIL_PASSWORD = credentials("cakemail-password-${params.ENVIRONMENT}")
541
+ }
542
+
543
+ stages {
544
+ stage('Setup') {
545
+ steps {
546
+ sh 'npm install -g @cakemail-org/cakemail-cli'
547
+ sh '''
548
+ echo "CAKEMAIL_EMAIL=$CAKEMAIL_EMAIL" > .env
549
+ echo "CAKEMAIL_PASSWORD=$CAKEMAIL_PASSWORD" >> .env
550
+ '''
551
+ }
552
+ }
553
+
554
+ stage('Get Environment Config') {
555
+ steps {
556
+ script {
557
+ def config = [
558
+ test: [list_id: '123', sender_id: '101'],
559
+ staging: [list_id: '124', sender_id: '102'],
560
+ production: [list_id: '125', sender_id: '103']
561
+ ]
562
+
563
+ env.LIST_ID = config[params.ENVIRONMENT].list_id
564
+ env.SENDER_ID = config[params.ENVIRONMENT].sender_id
565
+
566
+ echo "Deploying to ${params.ENVIRONMENT}"
567
+ echo "List ID: ${env.LIST_ID}"
568
+ echo "Sender ID: ${env.SENDER_ID}"
569
+ }
570
+ }
571
+ }
572
+
573
+ stage('Create Campaign') {
574
+ steps {
575
+ script {
576
+ def campaignId = sh(
577
+ script: """
578
+ cakemail campaigns create \
579
+ -n '[${params.ENVIRONMENT}] ${params.CAMPAIGN_NAME}' \
580
+ -l ${env.LIST_ID} \
581
+ -s ${env.SENDER_ID} \
582
+ --html-file campaigns/newsletter.html \
583
+ -f json | jq -r '.id'
584
+ """,
585
+ returnStdout: true
586
+ ).trim()
587
+
588
+ env.CAMPAIGN_ID = campaignId
589
+ }
590
+ }
591
+ }
592
+
593
+ stage('Schedule') {
594
+ when {
595
+ expression { params.AUTO_SCHEDULE == true }
596
+ }
597
+ steps {
598
+ sh 'cakemail campaigns schedule ${CAMPAIGN_ID}'
599
+ }
600
+ }
601
+ }
602
+ }
603
+ ```
604
+
605
+ ## Docker Integration
606
+
607
+ ### Dockerfile
608
+
609
+ ```dockerfile
610
+ # Dockerfile
611
+ FROM node:18-alpine
612
+
613
+ # Install Cakemail CLI
614
+ RUN npm install -g @cakemail-org/cakemail-cli
615
+
616
+ # Install additional tools
617
+ RUN apk add --no-cache \
618
+ bash \
619
+ jq \
620
+ curl
621
+
622
+ # Set working directory
623
+ WORKDIR /workspace
624
+
625
+ # Copy campaign files
626
+ COPY campaigns/ ./campaigns/
627
+ COPY scripts/ ./scripts/
628
+
629
+ # Set entrypoint
630
+ ENTRYPOINT ["bash"]
631
+ ```
632
+
633
+ ### Docker Compose Workflow
634
+
635
+ ```yaml
636
+ # docker-compose.yml
637
+ version: '3.8'
638
+
639
+ services:
640
+ cakemail-cli:
641
+ build: .
642
+ environment:
643
+ - CAKEMAIL_EMAIL=${CAKEMAIL_EMAIL}
644
+ - CAKEMAIL_PASSWORD=${CAKEMAIL_PASSWORD}
645
+ volumes:
646
+ - ./campaigns:/workspace/campaigns
647
+ - ./scripts:/workspace/scripts
648
+ - ./reports:/workspace/reports
649
+ command: /workspace/scripts/deploy-campaign.sh
650
+
651
+ scheduled-newsletter:
652
+ build: .
653
+ environment:
654
+ - CAKEMAIL_EMAIL=${CAKEMAIL_EMAIL}
655
+ - CAKEMAIL_PASSWORD=${CAKEMAIL_PASSWORD}
656
+ volumes:
657
+ - ./campaigns:/workspace/campaigns
658
+ command: /workspace/scripts/send-newsletter.sh
659
+ deploy:
660
+ restart_policy:
661
+ condition: none
662
+ ```
663
+
664
+ ### Docker Run Examples
665
+
666
+ ```bash
667
+ # One-off campaign deployment
668
+ docker run --rm \
669
+ -e CAKEMAIL_EMAIL="your@email.com" \
670
+ -e CAKEMAIL_PASSWORD="password" \
671
+ -v $(pwd)/campaigns:/workspace/campaigns \
672
+ cakemail-cli:latest \
673
+ -c "cakemail campaigns create -n 'Docker Campaign' -l 123 -s 101 --html-file campaigns/newsletter.html"
674
+
675
+ # Scheduled report generation
676
+ docker run --rm \
677
+ -e CAKEMAIL_EMAIL="your@email.com" \
678
+ -e CAKEMAIL_PASSWORD="password" \
679
+ -v $(pwd)/reports:/workspace/reports \
680
+ cakemail-cli:latest \
681
+ /workspace/scripts/generate-reports.sh
682
+ ```
683
+
684
+ ## CircleCI
685
+
686
+ ### Basic Configuration
687
+
688
+ ```yaml
689
+ # .circleci/config.yml
690
+ version: 2.1
691
+
692
+ executors:
693
+ cakemail:
694
+ docker:
695
+ - image: node:18
696
+ working_directory: ~/project
697
+
698
+ jobs:
699
+ deploy-campaign:
700
+ executor: cakemail
701
+ steps:
702
+ - checkout
703
+
704
+ - run:
705
+ name: Install CLI
706
+ command: npm install -g @cakemail-org/cakemail-cli
707
+
708
+ - run:
709
+ name: Configure
710
+ command: |
711
+ echo "CAKEMAIL_EMAIL=$CAKEMAIL_EMAIL" > .env
712
+ echo "CAKEMAIL_PASSWORD=$CAKEMAIL_PASSWORD" >> .env
713
+
714
+ - run:
715
+ name: Create campaign
716
+ command: |
717
+ CAMPAIGN_ID=$(cakemail campaigns create \
718
+ -n "Campaign $(date +%Y-%m-%d)" \
719
+ -l 123 \
720
+ -s 101 \
721
+ --html-file campaigns/newsletter.html \
722
+ -f json | jq -r '.id')
723
+ echo "export CAMPAIGN_ID=$CAMPAIGN_ID" >> $BASH_ENV
724
+
725
+ - run:
726
+ name: Test campaign
727
+ command: cakemail campaigns test $CAMPAIGN_ID -e test@company.com
728
+
729
+ - run:
730
+ name: Schedule campaign
731
+ command: cakemail campaigns schedule $CAMPAIGN_ID
732
+
733
+ workflows:
734
+ version: 2
735
+ deploy:
736
+ jobs:
737
+ - deploy-campaign:
738
+ filters:
739
+ branches:
740
+ only: main
741
+ context: cakemail-production
742
+ ```
743
+
744
+ ## Azure DevOps
745
+
746
+ ### Pipeline Configuration
747
+
748
+ ```yaml
749
+ # azure-pipelines.yml
750
+ trigger:
751
+ branches:
752
+ include:
753
+ - main
754
+ paths:
755
+ include:
756
+ - campaigns/*
757
+
758
+ pool:
759
+ vmImage: 'ubuntu-latest'
760
+
761
+ variables:
762
+ LIST_ID: 123
763
+ SENDER_ID: 101
764
+
765
+ steps:
766
+ - task: NodeTool@0
767
+ inputs:
768
+ versionSpec: '18.x'
769
+ displayName: 'Install Node.js'
770
+
771
+ - script: |
772
+ npm install -g @cakemail-org/cakemail-cli
773
+ displayName: 'Install Cakemail CLI'
774
+
775
+ - task: Bash@3
776
+ inputs:
777
+ targetType: 'inline'
778
+ script: |
779
+ echo "CAKEMAIL_EMAIL=$(CAKEMAIL_EMAIL)" > .env
780
+ echo "CAKEMAIL_PASSWORD=$(CAKEMAIL_PASSWORD)" >> .env
781
+ displayName: 'Configure credentials'
782
+ env:
783
+ CAKEMAIL_EMAIL: $(CAKEMAIL_EMAIL)
784
+ CAKEMAIL_PASSWORD: $(CAKEMAIL_PASSWORD)
785
+
786
+ - script: |
787
+ CAMPAIGN_ID=$(cakemail campaigns create \
788
+ -n "Campaign $(date +%Y-%m-%d)" \
789
+ -l $(LIST_ID) \
790
+ -s $(SENDER_ID) \
791
+ --html-file campaigns/newsletter.html \
792
+ -f json | jq -r '.id')
793
+ echo "##vso[task.setvariable variable=campaignId]$CAMPAIGN_ID"
794
+ echo "Created campaign: $CAMPAIGN_ID"
795
+ displayName: 'Create campaign'
796
+
797
+ - script: |
798
+ cakemail campaigns test $(campaignId) -e test@company.com
799
+ displayName: 'Send test email'
800
+
801
+ - script: |
802
+ cakemail campaigns schedule $(campaignId)
803
+ displayName: 'Schedule campaign'
804
+ condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
805
+ ```
806
+
807
+ ## Best Practices
808
+
809
+ ### 1. Secure Credential Management
810
+
811
+ ```yaml
812
+ # Use encrypted secrets
813
+ env:
814
+ CAKEMAIL_EMAIL: ${{ secrets.CAKEMAIL_EMAIL }}
815
+ CAKEMAIL_PASSWORD: ${{ secrets.CAKEMAIL_PASSWORD }}
816
+
817
+ # Never commit credentials
818
+ echo ".env" >> .gitignore
819
+ ```
820
+
821
+ ### 2. Environment Separation
822
+
823
+ ```bash
824
+ # Use different accounts/lists per environment
825
+ TEST_LIST_ID=123
826
+ STAGING_LIST_ID=124
827
+ PROD_LIST_ID=125
828
+ ```
829
+
830
+ ### 3. Automated Testing
831
+
832
+ ```yaml
833
+ - name: Validate HTML
834
+ run: html-validator campaigns/*.html
835
+
836
+ - name: Check subject line length
837
+ run: |
838
+ SUBJECT=$(cat campaigns/subject.txt)
839
+ LENGTH=${#SUBJECT}
840
+ if [ $LENGTH -gt 60 ]; then
841
+ echo "Subject too long: $LENGTH chars"
842
+ exit 1
843
+ fi
844
+ ```
845
+
846
+ ### 4. Rollback Strategy
847
+
848
+ ```bash
849
+ # Save campaign ID for rollback
850
+ echo "$CAMPAIGN_ID" > .last-deployment
851
+
852
+ # Rollback if needed
853
+ LAST_ID=$(cat .last-deployment)
854
+ cakemail campaigns unschedule "$LAST_ID"
855
+ ```
856
+
857
+ ### 5. Notifications
858
+
859
+ ```yaml
860
+ - name: Notify success
861
+ if: success()
862
+ run: |
863
+ curl -X POST $SLACK_WEBHOOK \
864
+ -d '{"text":"✅ Campaign deployed"}'
865
+
866
+ - name: Notify failure
867
+ if: failure()
868
+ run: |
869
+ curl -X POST $SLACK_WEBHOOK \
870
+ -d '{"text":"❌ Campaign deployment failed"}'
871
+ ```
872
+
873
+ ### 6. Logging and Auditing
874
+
875
+ ```bash
876
+ # Log all operations
877
+ exec 1> >(tee -a deploy.log)
878
+ exec 2>&1
879
+
880
+ echo "[$(date)] Starting deployment..."
881
+ ```
882
+
883
+ ### 7. Conditional Deployment
884
+
885
+ ```yaml
886
+ - name: Deploy
887
+ if: |
888
+ github.ref == 'refs/heads/main' &&
889
+ contains(github.event.head_commit.message, '[deploy]')
890
+ run: ./scripts/deploy.sh
891
+ ```
892
+