@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,630 @@
1
+ # Campaign Scheduling
2
+
3
+ Master campaign scheduling to send emails at optimal times and manage scheduled campaigns.
4
+
5
+ ## Overview
6
+
7
+ Scheduling allows you to:
8
+ - Send campaigns immediately
9
+ - Schedule campaigns for future delivery
10
+ - Reschedule pending campaigns
11
+ - Unschedule campaigns to return to draft
12
+ - Control exact send time for optimal engagement
13
+
14
+ ## Scheduling Basics
15
+
16
+ ### Immediate Send
17
+
18
+ Send campaign right away:
19
+
20
+ ```bash
21
+ $ cakemail campaigns schedule 790
22
+ ```
23
+
24
+ **Output:**
25
+ ```
26
+ ✓ Campaign 790 scheduled for immediate delivery
27
+ ```
28
+
29
+ Campaign status changes: `draft` → `scheduled` → `sending` → `sent`
30
+
31
+ ### Schedule for Future
32
+
33
+ Specify exact date and time:
34
+
35
+ ```bash
36
+ $ cakemail campaigns schedule 790 --when "2024-03-20 10:00:00"
37
+ ```
38
+
39
+ **Output:**
40
+ ```
41
+ ✓ Campaign 790 scheduled for 2024-03-20 10:00:00 UTC
42
+ ```
43
+
44
+ ### Timezone Considerations
45
+
46
+ By default, times are in UTC. Use your local timezone:
47
+
48
+ ```bash
49
+ # Schedule for 10 AM Eastern Time
50
+ $ cakemail campaigns schedule 790 --when "2024-03-20 10:00:00 -0400"
51
+
52
+ # Schedule for 10 AM Pacific Time
53
+ $ cakemail campaigns schedule 790 --when "2024-03-20 10:00:00 -0700"
54
+ ```
55
+
56
+ ## Checking Scheduled Campaigns
57
+
58
+ ### List All Scheduled Campaigns
59
+
60
+ ```bash
61
+ $ cakemail campaigns list --filter "status==scheduled"
62
+ ```
63
+
64
+ **Output:**
65
+ ```
66
+ ┌────────┬────────────────────┬─────────────────────┬─────────────────────┐
67
+ │ ID │ Name │ Scheduled For │ List │
68
+ ├────────┼────────────────────┼─────────────────────┼─────────────────────┤
69
+ │ 790 │ March Newsletter │ 2024-03-20 10:00:00 │ Newsletter (123) │
70
+ │ 791 │ Product Update │ 2024-03-21 14:00:00 │ Customers (124) │
71
+ └────────┴────────────────────┴─────────────────────┴─────────────────────┘
72
+ ```
73
+
74
+ ### View Scheduled Time
75
+
76
+ ```bash
77
+ $ cakemail campaigns get 790 -f json | jq '{id, name, status, scheduled_for}'
78
+ ```
79
+
80
+ **Output:**
81
+ ```json
82
+ {
83
+ "id": 790,
84
+ "name": "March Newsletter",
85
+ "status": "scheduled",
86
+ "scheduled_for": "2024-03-20T10:00:00Z"
87
+ }
88
+ ```
89
+
90
+ ## Rescheduling Campaigns
91
+
92
+ ### Change Scheduled Time
93
+
94
+ ```bash
95
+ $ cakemail campaigns reschedule 790 --when "2024-03-21 10:00:00"
96
+ ```
97
+
98
+ **Output:**
99
+ ```
100
+ ✓ Campaign 790 rescheduled for 2024-03-21 10:00:00 UTC
101
+ ```
102
+
103
+ ### Move to Earlier Time
104
+
105
+ ```bash
106
+ # Originally scheduled for March 20
107
+ $ cakemail campaigns reschedule 790 --when "2024-03-19 10:00:00"
108
+ ```
109
+
110
+ **Output:**
111
+ ```
112
+ ✓ Campaign 790 rescheduled for 2024-03-19 10:00:00 UTC
113
+ ```
114
+
115
+ ### Reschedule to Immediate
116
+
117
+ ```bash
118
+ $ cakemail campaigns reschedule 790 --now
119
+ ```
120
+
121
+ **Output:**
122
+ ```
123
+ ✓ Campaign 790 rescheduled for immediate delivery
124
+ ```
125
+
126
+ ## Unscheduling Campaigns
127
+
128
+ ### Return to Draft Status
129
+
130
+ Cancel scheduled send and return campaign to draft:
131
+
132
+ ```bash
133
+ $ cakemail campaigns unschedule 790
134
+ ```
135
+
136
+ **Output:**
137
+ ```
138
+ ✓ Campaign 790 unscheduled (returned to draft)
139
+ ```
140
+
141
+ Campaign status changes: `scheduled` → `draft`
142
+
143
+ **Use cases:**
144
+ - Need to make changes to content
145
+ - Wrong list or sender selected
146
+ - Scheduling mistake
147
+ - Market conditions changed
148
+
149
+ ### Make Changes After Unscheduling
150
+
151
+ ```bash
152
+ # Unschedule
153
+ $ cakemail campaigns unschedule 790
154
+
155
+ # Make changes
156
+ $ cakemail campaigns update 790 --subject "Updated Subject"
157
+
158
+ # Reschedule
159
+ $ cakemail campaigns schedule 790 --when "2024-03-21 10:00:00"
160
+ ```
161
+
162
+ ## Best Send Times
163
+
164
+ ### Industry Standards
165
+
166
+ **B2B (Business):**
167
+ - Tuesday-Thursday: 10 AM - 11 AM
168
+ - Avoid: Monday mornings, Friday afternoons
169
+
170
+ **B2C (Consumer):**
171
+ - Tuesday-Thursday: 8 AM - 10 AM
172
+ - Saturday: 10 AM - 12 PM
173
+ - Avoid: Late night, early morning
174
+
175
+ **E-commerce:**
176
+ - Tuesday-Thursday: 8 PM - 10 PM
177
+ - Sunday: 6 PM - 9 PM
178
+ - Friday: 12 PM - 2 PM (payday effect)
179
+
180
+ ### Testing Your Audience
181
+
182
+ Find your optimal send time:
183
+
184
+ ```bash
185
+ #!/bin/bash
186
+ # Test different send times
187
+
188
+ # Week 1: Tuesday 10 AM
189
+ cakemail campaigns create -n "Test - Tue 10AM" -l 123 -s 101
190
+ cakemail campaigns schedule 792 --when "2024-03-19 10:00:00"
191
+
192
+ # Week 2: Thursday 2 PM
193
+ cakemail campaigns create -n "Test - Thu 2PM" -l 123 -s 101
194
+ cakemail campaigns schedule 793 --when "2024-03-21 14:00:00"
195
+
196
+ # Week 3: Saturday 10 AM
197
+ cakemail campaigns create -n "Test - Sat 10AM" -l 123 -s 101
198
+ cakemail campaigns schedule 794 --when "2024-03-23 10:00:00"
199
+
200
+ # Compare open rates
201
+ cakemail reports campaign 792 -f json | jq '.open_rate'
202
+ cakemail reports campaign 793 -f json | jq '.open_rate'
203
+ cakemail reports campaign 794 -f json | jq '.open_rate'
204
+ ```
205
+
206
+ ## Scheduling Workflows
207
+
208
+ ### Workflow 1: Weekly Newsletter
209
+
210
+ ```bash
211
+ #!/bin/bash
212
+ # schedule-weekly-newsletter.sh
213
+
214
+ # Create campaign
215
+ CAMPAIGN_ID=$(cakemail campaigns create \
216
+ -n "Weekly Newsletter $(date +%Y-%m-%d)" \
217
+ -l 123 \
218
+ -s 101 \
219
+ --template 201 \
220
+ --subject "This Week's Updates" \
221
+ -f json | jq -r '.id')
222
+
223
+ echo "Created campaign: $CAMPAIGN_ID"
224
+
225
+ # Send test
226
+ cakemail campaigns test $CAMPAIGN_ID -e editor@company.com
227
+ echo "Test sent. Review and approve."
228
+
229
+ # Schedule for next Tuesday at 10 AM
230
+ NEXT_TUESDAY=$(date -d "next tuesday" +%Y-%m-%d)
231
+ cakemail campaigns schedule $CAMPAIGN_ID --when "$NEXT_TUESDAY 10:00:00"
232
+
233
+ echo "Scheduled for $NEXT_TUESDAY at 10:00 AM"
234
+ ```
235
+
236
+ ### Workflow 2: Content Calendar
237
+
238
+ ```bash
239
+ #!/bin/bash
240
+ # schedule-content-calendar.sh
241
+
242
+ # March content calendar
243
+ declare -A CAMPAIGNS=(
244
+ ["2024-03-05"]="Product Launch Announcement"
245
+ ["2024-03-12"]="Customer Success Stories"
246
+ ["2024-03-19"]="Spring Sale Preview"
247
+ ["2024-03-26"]="Tips & Best Practices"
248
+ )
249
+
250
+ for date in "${!CAMPAIGNS[@]}"; do
251
+ name="${CAMPAIGNS[$date]}"
252
+
253
+ # Create campaign
254
+ ID=$(cakemail campaigns create \
255
+ -n "$name" \
256
+ -l 123 \
257
+ -s 101 \
258
+ -f json | jq -r '.id')
259
+
260
+ # Schedule for 10 AM on date
261
+ cakemail campaigns schedule $ID --when "$date 10:00:00"
262
+
263
+ echo "Scheduled: $name for $date"
264
+ done
265
+
266
+ # List all scheduled
267
+ cakemail campaigns list --filter "status==scheduled" --sort "+scheduled_for"
268
+ ```
269
+
270
+ ### Workflow 3: A/B Send Time Testing
271
+
272
+ ```bash
273
+ #!/bin/bash
274
+ # ab-test-send-times.sh
275
+
276
+ # Same content, different times
277
+ TEMPLATE=201
278
+ LIST=123
279
+ SENDER=101
280
+ SUBJECT="March Newsletter"
281
+
282
+ # Version A: Tuesday 10 AM
283
+ ID_A=$(cakemail campaigns create \
284
+ -n "A/B Test - Version A" \
285
+ -l $LIST \
286
+ -s $SENDER \
287
+ --template $TEMPLATE \
288
+ --subject "$SUBJECT" \
289
+ -f json | jq -r '.id')
290
+
291
+ cakemail campaigns schedule $ID_A --when "2024-03-19 10:00:00"
292
+
293
+ # Version B: Thursday 2 PM
294
+ ID_B=$(cakemail campaigns create \
295
+ -n "A/B Test - Version B" \
296
+ -l $LIST \
297
+ -s $SENDER \
298
+ --template $TEMPLATE \
299
+ --subject "$SUBJECT" \
300
+ -f json | jq -r '.id')
301
+
302
+ cakemail campaigns schedule $ID_B --when "2024-03-21 14:00:00"
303
+
304
+ echo "A/B test scheduled:"
305
+ echo "Version A (Tue 10AM): $ID_A"
306
+ echo "Version B (Thu 2PM): $ID_B"
307
+
308
+ # Compare results after both send
309
+ echo ""
310
+ echo "Run after both campaigns send:"
311
+ echo "cakemail reports campaign $ID_A"
312
+ echo "cakemail reports campaign $ID_B"
313
+ ```
314
+
315
+ ### Workflow 4: Automated Daily Digest
316
+
317
+ ```bash
318
+ #!/bin/bash
319
+ # schedule-daily-digest.sh
320
+ # Run this script daily via cron
321
+
322
+ TODAY=$(date +%Y-%m-%d)
323
+ TOMORROW=$(date -d "tomorrow" +%Y-%m-%d)
324
+
325
+ # Create digest
326
+ ID=$(cakemail campaigns create \
327
+ -n "Daily Digest - $TOMORROW" \
328
+ -l 123 \
329
+ -s 101 \
330
+ --subject "Your Daily Digest - $TOMORROW" \
331
+ -f json | jq -r '.id')
332
+
333
+ # Add dynamic content (your script)
334
+ # ... generate digest content ...
335
+
336
+ # Schedule for tomorrow 7 AM
337
+ cakemail campaigns schedule $ID --when "$TOMORROW 07:00:00"
338
+
339
+ echo "Tomorrow's digest scheduled: $ID"
340
+ ```
341
+
342
+ ## Scheduling Calendar View
343
+
344
+ Create a scheduling calendar:
345
+
346
+ ```bash
347
+ #!/bin/bash
348
+ # show-scheduling-calendar.sh
349
+
350
+ echo "=== Scheduling Calendar ==="
351
+ echo ""
352
+
353
+ # Get all scheduled campaigns
354
+ CAMPAIGNS=$(cakemail campaigns list \
355
+ --filter "status==scheduled" \
356
+ --sort "+scheduled_for" \
357
+ -f json)
358
+
359
+ # Group by date
360
+ echo "$CAMPAIGNS" | jq -r '
361
+ .data[] |
362
+ "\(.scheduled_for | split("T")[0]) \(.scheduled_for | split("T")[1] | split(".")[0]) - \(.name) (ID: \(.id))"
363
+ ' | while read line; do
364
+ echo " $line"
365
+ done
366
+
367
+ echo ""
368
+ echo "Total scheduled: $(echo "$CAMPAIGNS" | jq '.count')"
369
+ ```
370
+
371
+ **Output:**
372
+ ```
373
+ === Scheduling Calendar ===
374
+
375
+ 2024-03-19 10:00:00 - March Newsletter (ID: 790)
376
+ 2024-03-20 14:00:00 - Product Update (ID: 791)
377
+ 2024-03-21 10:00:00 - Weekly Digest (ID: 792)
378
+ 2024-03-23 09:00:00 - Weekend Special (ID: 793)
379
+
380
+ Total scheduled: 4
381
+ ```
382
+
383
+ ## Pre-Flight Checklist
384
+
385
+ Before scheduling, verify:
386
+
387
+ ```bash
388
+ #!/bin/bash
389
+ # pre-flight-check.sh
390
+
391
+ CAMPAIGN_ID=$1
392
+
393
+ if [ -z "$CAMPAIGN_ID" ]; then
394
+ echo "Usage: $0 <campaign-id>"
395
+ exit 1
396
+ fi
397
+
398
+ echo "=== Pre-Flight Check for Campaign $CAMPAIGN_ID ==="
399
+ echo ""
400
+
401
+ # Get campaign details
402
+ CAMPAIGN=$(cakemail campaigns get $CAMPAIGN_ID -f json)
403
+
404
+ # Check 1: Has content
405
+ HAS_HTML=$(echo "$CAMPAIGN" | jq -r '.html' | grep -v "null")
406
+ if [ -z "$HAS_HTML" ]; then
407
+ echo "❌ Missing HTML content"
408
+ exit 1
409
+ else
410
+ echo "✅ HTML content present"
411
+ fi
412
+
413
+ # Check 2: Has subject
414
+ SUBJECT=$(echo "$CAMPAIGN" | jq -r '.subject')
415
+ if [ "$SUBJECT" == "null" ] || [ -z "$SUBJECT" ]; then
416
+ echo "❌ Missing subject line"
417
+ exit 1
418
+ else
419
+ echo "✅ Subject: $SUBJECT"
420
+ fi
421
+
422
+ # Check 3: Valid sender
423
+ SENDER_ID=$(echo "$CAMPAIGN" | jq -r '.sender_id')
424
+ SENDER_CONFIRMED=$(cakemail senders get $SENDER_ID -f json | jq -r '.confirmed')
425
+ if [ "$SENDER_CONFIRMED" != "true" ]; then
426
+ echo "❌ Sender not confirmed"
427
+ exit 1
428
+ else
429
+ echo "✅ Sender confirmed"
430
+ fi
431
+
432
+ # Check 4: List has contacts
433
+ LIST_ID=$(echo "$CAMPAIGN" | jq -r '.list_id')
434
+ CONTACT_COUNT=$(cakemail contacts list $LIST_ID -f json | jq '.count')
435
+ if [ "$CONTACT_COUNT" -eq 0 ]; then
436
+ echo "⚠️ Warning: List has 0 contacts"
437
+ else
438
+ echo "✅ List has $CONTACT_COUNT contacts"
439
+ fi
440
+
441
+ echo ""
442
+ echo "✅ All checks passed! Ready to schedule."
443
+ ```
444
+
445
+ ## Common Scheduling Patterns
446
+
447
+ ### Pattern 1: Schedule Series
448
+
449
+ Schedule multiple campaigns in sequence:
450
+
451
+ ```bash
452
+ #!/bin/bash
453
+ # schedule-series.sh
454
+
455
+ DATES=("2024-03-19" "2024-03-26" "2024-04-02" "2024-04-09")
456
+ TEMPLATE=201
457
+ LIST=123
458
+ SENDER=101
459
+
460
+ for i in "${!DATES[@]}"; do
461
+ week=$((i + 1))
462
+ date="${DATES[$i]}"
463
+
464
+ ID=$(cakemail campaigns create \
465
+ -n "Week $week Newsletter" \
466
+ -l $LIST \
467
+ -s $SENDER \
468
+ --template $TEMPLATE \
469
+ --subject "Week $week Updates" \
470
+ -f json | jq -r '.id')
471
+
472
+ cakemail campaigns schedule $ID --when "$date 10:00:00"
473
+ echo "Week $week scheduled for $date"
474
+ done
475
+ ```
476
+
477
+ ### Pattern 2: Batch Scheduling
478
+
479
+ Schedule multiple campaigns at once:
480
+
481
+ ```bash
482
+ #!/bin/bash
483
+ # batch-schedule.sh
484
+
485
+ # Array of campaign IDs ready to schedule
486
+ CAMPAIGNS=(790 791 792 793)
487
+
488
+ # Schedule all for next Monday 10 AM
489
+ NEXT_MONDAY=$(date -d "next monday" +%Y-%m-%d)
490
+
491
+ for ID in "${CAMPAIGNS[@]}"; do
492
+ cakemail campaigns schedule $ID --when "$NEXT_MONDAY 10:00:00"
493
+ echo "Campaign $ID scheduled for $NEXT_MONDAY"
494
+ done
495
+ ```
496
+
497
+ ### Pattern 3: Smart Rescheduling
498
+
499
+ Reschedule if within threshold:
500
+
501
+ ```bash
502
+ #!/bin/bash
503
+ # smart-reschedule.sh
504
+
505
+ CAMPAIGN_ID=$1
506
+ NEW_TIME=$2
507
+
508
+ # Get current scheduled time
509
+ CURRENT=$(cakemail campaigns get $CAMPAIGN_ID -f json | jq -r '.scheduled_for')
510
+
511
+ # Calculate time until send
512
+ CURRENT_TS=$(date -d "$CURRENT" +%s)
513
+ NOW_TS=$(date +%s)
514
+ HOURS_UNTIL=$((($CURRENT_TS - $NOW_TS) / 3600))
515
+
516
+ # Only reschedule if more than 2 hours away
517
+ if [ $HOURS_UNTIL -gt 2 ]; then
518
+ cakemail campaigns reschedule $CAMPAIGN_ID --when "$NEW_TIME"
519
+ echo "Campaign rescheduled"
520
+ else
521
+ echo "Too close to send time ($HOURS_UNTIL hours). Unschedule first if needed."
522
+ exit 1
523
+ fi
524
+ ```
525
+
526
+ ## Troubleshooting
527
+
528
+ ### Cannot Schedule Campaign
529
+
530
+ **Error:** "Campaign not in draft status"
531
+
532
+ **Solution:**
533
+ ```bash
534
+ # Check current status
535
+ $ cakemail campaigns get 790 -f json | jq '.status'
536
+
537
+ # If "scheduled", unschedule first
538
+ $ cakemail campaigns unschedule 790
539
+
540
+ # Then schedule again
541
+ $ cakemail campaigns schedule 790 --when "2024-03-21 10:00:00"
542
+ ```
543
+
544
+ ### Invalid Date Format
545
+
546
+ **Error:** "Invalid date format"
547
+
548
+ **Solution:**
549
+ ```bash
550
+ # ✅ Correct formats:
551
+ --when "2024-03-20 10:00:00"
552
+ --when "2024-03-20T10:00:00Z"
553
+ --when "2024-03-20 10:00:00 -0400"
554
+
555
+ # ❌ Incorrect formats:
556
+ --when "03/20/2024 10:00 AM"
557
+ --when "March 20, 2024 10:00"
558
+ --when "20-03-2024 10:00"
559
+ ```
560
+
561
+ ### Campaign Sent at Wrong Time
562
+
563
+ **Problem:** Campaign sent at unexpected time
564
+
565
+ **Possible causes:**
566
+ 1. **Timezone confusion** - UTC vs local time
567
+ 2. **Daylight saving** - Time shift during DST change
568
+ 3. **Incorrect date** - Typo in date/time
569
+
570
+ **Prevention:**
571
+ ```bash
572
+ # Always verify scheduled time
573
+ $ cakemail campaigns get 790 -f json | jq '.scheduled_for'
574
+
575
+ # Use timezone-aware scheduling
576
+ $ cakemail campaigns schedule 790 --when "2024-03-20 10:00:00 -0400"
577
+ ```
578
+
579
+ ### Cannot Reschedule
580
+
581
+ **Error:** "Campaign too close to send time"
582
+
583
+ **Solution:**
584
+ ```bash
585
+ # Unschedule first
586
+ $ cakemail campaigns unschedule 790
587
+
588
+ # Make changes
589
+ $ cakemail campaigns update 790 --subject "Updated"
590
+
591
+ # Reschedule
592
+ $ cakemail campaigns schedule 790 --when "2024-03-25 10:00:00"
593
+ ```
594
+
595
+ ## Best Practices
596
+
597
+ 1. **Test Before Scheduling**
598
+ ```bash
599
+ cakemail campaigns test 790 -e test@company.com
600
+ # Review test, then schedule
601
+ cakemail campaigns schedule 790 --when "..."
602
+ ```
603
+
604
+ 2. **Avoid Last-Minute Scheduling**
605
+ - Schedule at least 2 hours in advance
606
+ - Allows time for final reviews
607
+ - Buffer for technical issues
608
+
609
+ 3. **Use Consistent Times**
610
+ - Train audience to expect emails
611
+ - Example: Every Tuesday 10 AM
612
+ - Improves open rates
613
+
614
+ 4. **Document Your Calendar**
615
+ ```bash
616
+ # Keep scheduling log
617
+ echo "$(date): Scheduled campaign 790 for 2024-03-20" >> campaign-log.txt
618
+ ```
619
+
620
+ 5. **Monitor Scheduled Campaigns**
621
+ ```bash
622
+ # Daily check
623
+ cakemail campaigns list --filter "status==scheduled"
624
+ ```
625
+
626
+ 6. **Set Reminders**
627
+ - Remind to review 24h before send
628
+ - Final check 2h before send
629
+ - Post-send analytics review
630
+