@cakemail-org/cakemail-cli 1.7.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.
- package/.claude/settings.local.json +12 -0
- package/.env.example +40 -0
- package/.env.test.example +45 -0
- package/CHANGELOG.md +1031 -0
- package/README.md +41 -37
- package/audit-formats.js +128 -0
- package/cakemail.rb +20 -0
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/dist/commands/account.js +1 -1
- package/dist/commands/account.js.map +1 -1
- package/dist/commands/attributes.js +1 -1
- package/dist/commands/attributes.js.map +1 -1
- package/dist/commands/campaigns.js +1 -1
- package/dist/commands/campaigns.js.map +1 -1
- package/dist/commands/contacts.js +1 -1
- package/dist/commands/contacts.js.map +1 -1
- package/dist/commands/emails.js +1 -1
- package/dist/commands/emails.js.map +1 -1
- package/dist/commands/interests.js +1 -1
- package/dist/commands/interests.js.map +1 -1
- package/dist/commands/lists.js +1 -1
- package/dist/commands/lists.js.map +1 -1
- package/dist/commands/logs.js +1 -1
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/reports.js +1 -1
- package/dist/commands/reports.js.map +1 -1
- package/dist/commands/segments.js +1 -1
- package/dist/commands/segments.js.map +1 -1
- package/dist/commands/senders.js +1 -1
- package/dist/commands/senders.js.map +1 -1
- package/dist/commands/suppressed.js +1 -1
- package/dist/commands/suppressed.js.map +1 -1
- package/dist/commands/tags.js +1 -1
- package/dist/commands/tags.js.map +1 -1
- package/dist/commands/templates.js +1 -1
- package/dist/commands/templates.js.map +1 -1
- package/dist/commands/transactional-templates.js +1 -1
- package/dist/commands/transactional-templates.js.map +1 -1
- package/dist/commands/webhooks.js +1 -1
- package/dist/commands/webhooks.js.map +1 -1
- package/dist/utils/config.js +2 -2
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/errors.js +1 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/progress.d.ts.map +1 -1
- package/dist/utils/progress.js +32 -4
- package/dist/utils/progress.js.map +1 -1
- package/dist/utils/spinner.d.ts +17 -0
- package/dist/utils/spinner.d.ts.map +1 -0
- package/dist/utils/spinner.js +43 -0
- package/dist/utils/spinner.js.map +1 -0
- package/docs/DOCUMENTATION-STANDARD.md +1068 -0
- package/docs/README.md +161 -0
- package/docs/developer/ARCHITECTURE.md +516 -0
- package/docs/developer/AUTH.md +204 -0
- package/docs/developer/CONTRIBUTING.md +227 -0
- package/docs/developer/DOCUMENTATION_SUMMARY.md +346 -0
- package/docs/developer/PROJECT_INDEX.md +365 -0
- package/docs/planning/API_COVERAGE.md +1045 -0
- package/docs/planning/BACKLOG.md +1159 -0
- package/docs/planning/PROFILE_SYSTEM_TASKS.md +287 -0
- package/docs/planning/UX_IMPLEMENTATION_PLAN.md +691 -0
- package/docs/planning/archive/RELEASE_CHECKLIST_v1.3.0.md +332 -0
- package/docs/planning/archive/RELEASE_v1.3.0.md +428 -0
- package/docs/planning/archive/cakemail-cli-ux-improvements.md +438 -0
- package/docs/planning/cakemail-profile-system-plan.md +1121 -0
- package/docs/testing/AI_USER_SIMULATION_DESIGN.md +1342 -0
- package/docs/testing/KENOGAMI_BIDIRECTIONAL_FLOW.md +1517 -0
- package/docs/testing/KENOGAMI_TRUTH_RECONCILIATION_SYSTEM.md +1369 -0
- package/docs/user-manual/.obsidian/app.json +1 -0
- package/docs/user-manual/.obsidian/appearance.json +1 -0
- package/docs/user-manual/.obsidian/core-plugins.json +33 -0
- package/docs/user-manual/.obsidian/workspace.json +167 -0
- package/docs/user-manual/01-getting-started/01-installation.md +214 -0
- package/docs/user-manual/01-getting-started/02-quick-start.md +432 -0
- package/docs/user-manual/01-getting-started/03-authentication.md +448 -0
- package/docs/user-manual/01-getting-started/04-configuration.md +430 -0
- package/docs/user-manual/01-getting-started/05-output-formats.md +447 -0
- package/docs/user-manual/02-core-concepts/01-accounts.md +514 -0
- package/docs/user-manual/02-core-concepts/02-profile-system.md +771 -0
- package/docs/user-manual/02-core-concepts/03-smart-defaults.md +485 -0
- package/docs/user-manual/02-core-concepts/04-authentication-methods.md +435 -0
- package/docs/user-manual/02-core-concepts/05-pagination-filtering.md +600 -0
- package/docs/user-manual/02-core-concepts/06-error-handling.md +718 -0
- package/docs/user-manual/02-core-concepts/07-api-coverage.md +483 -0
- package/docs/user-manual/03-email-operations/01-senders.md +490 -0
- package/docs/user-manual/03-email-operations/02-templates.md +444 -0
- package/docs/user-manual/03-email-operations/03-transactional-emails.md +706 -0
- package/docs/user-manual/03-email-operations/04-email-tracking.md +407 -0
- package/docs/user-manual/04-campaign-management/01-campaigns-basics.md +394 -0
- package/docs/user-manual/04-campaign-management/02-campaign-scheduling.md +630 -0
- package/docs/user-manual/04-campaign-management/03-campaign-testing.md +997 -0
- package/docs/user-manual/04-campaign-management/04-campaign-lifecycle.md +709 -0
- package/docs/user-manual/04-campaign-management/05-campaign-links.md +934 -0
- package/docs/user-manual/05-contact-management/01-lists.md +836 -0
- package/docs/user-manual/05-contact-management/02-contacts.md +1035 -0
- package/docs/user-manual/05-contact-management/03-custom-attributes.md +788 -0
- package/docs/user-manual/05-contact-management/04-segments.md +1028 -0
- package/docs/user-manual/05-contact-management/05-contact-import-export.md +1031 -0
- package/docs/user-manual/06-analytics-reporting/01-campaign-analytics.md +867 -0
- package/docs/user-manual/06-analytics-reporting/02-account-reports.md +227 -0
- package/docs/user-manual/07-integrations/01-webhooks-integration.md +259 -0
- package/docs/user-manual/07-integrations/02-automation.md +326 -0
- package/docs/user-manual/08-advanced-usage/01-scripting-patterns.md +672 -0
- package/docs/user-manual/08-advanced-usage/02-bulk-operations.md +932 -0
- package/docs/user-manual/08-advanced-usage/03-ci-cd-integration.md +892 -0
- package/docs/user-manual/08-advanced-usage/04-performance-optimization.md +766 -0
- package/docs/user-manual/09-command-reference/01-config.md +776 -0
- package/docs/user-manual/09-command-reference/02-account.md +652 -0
- package/docs/user-manual/09-command-reference/03-lists.md +958 -0
- package/docs/user-manual/09-command-reference/04-contacts.md +1408 -0
- package/docs/user-manual/09-command-reference/05-attributes.md +617 -0
- package/docs/user-manual/09-command-reference/06-segments.md +894 -0
- package/docs/user-manual/09-command-reference/07-senders.md +803 -0
- package/docs/user-manual/09-command-reference/08-templates.md +818 -0
- package/docs/user-manual/09-command-reference/09-campaigns.md +1250 -0
- package/docs/user-manual/09-command-reference/10-emails.md +807 -0
- package/docs/user-manual/09-command-reference/11-reports.md +1135 -0
- package/docs/user-manual/09-command-reference/12-webhooks.md +773 -0
- package/docs/user-manual/09-command-reference/13-suppressed.md +797 -0
- package/docs/user-manual/09-command-reference/14-interests.md +630 -0
- package/docs/user-manual/09-command-reference/15-tags.md +584 -0
- package/docs/user-manual/09-command-reference/16-logs.md +656 -0
- package/docs/user-manual/09-command-reference/17-transactional-templates.md +850 -0
- package/docs/user-manual/10-troubleshooting/01-common-errors.md +457 -0
- package/docs/user-manual/10-troubleshooting/02-authentication-issues.md +558 -0
- package/docs/user-manual/10-troubleshooting/03-connection-problems.md +634 -0
- package/docs/user-manual/10-troubleshooting/04-debugging.md +725 -0
- package/docs/user-manual/11-appendix/04-faq.md +484 -0
- package/docs/user-manual/11-appendix/05-glossary.md +250 -0
- package/docs/user-manual/README.md +0 -0
- package/package.json +13 -61
- package/src/cli.ts +125 -0
- package/src/client.ts +16 -0
- package/src/commands/account.ts +267 -0
- package/src/commands/accounts.ts +78 -0
- package/src/commands/actions.ts +249 -0
- package/src/commands/attributes.ts +139 -0
- package/src/commands/campaign-blueprints.ts +106 -0
- package/src/commands/campaigns.ts +469 -0
- package/src/commands/config.ts +77 -0
- package/src/commands/contacts.ts +612 -0
- package/src/commands/custom-attributes.ts +127 -0
- package/src/commands/dkims.ts +117 -0
- package/src/commands/domains.ts +82 -0
- package/src/commands/email-apis.ts +569 -0
- package/src/commands/emails.ts +197 -0
- package/src/commands/forms.ts +283 -0
- package/src/commands/interests.ts +155 -0
- package/src/commands/links.ts +38 -0
- package/src/commands/lists.ts +406 -0
- package/src/commands/logos.ts +71 -0
- package/src/commands/logs.ts +386 -0
- package/src/commands/reports.ts +306 -0
- package/src/commands/segments.ts +158 -0
- package/src/commands/senders.ts +204 -0
- package/src/commands/sub-accounts.ts +271 -0
- package/src/commands/suppressed-emails.ts +234 -0
- package/src/commands/suppressed.ts +198 -0
- package/src/commands/system-emails.ts +85 -0
- package/src/commands/tags.ts +146 -0
- package/src/commands/tasks.ts +116 -0
- package/src/commands/templates.ts +189 -0
- package/src/commands/tokens.ts +83 -0
- package/src/commands/transactional-emails.ts +374 -0
- package/src/commands/transactional-templates.ts +385 -0
- package/src/commands/users.ts +506 -0
- package/src/commands/webhooks.ts +172 -0
- package/src/commands/workflow-blueprints.ts +123 -0
- package/src/commands/workflows.ts +265 -0
- package/src/types/profile.ts +93 -0
- package/src/utils/auth.ts +272 -0
- package/src/utils/config-file.ts +96 -0
- package/src/utils/config.ts +134 -0
- package/src/utils/confirm.ts +32 -0
- package/src/utils/defaults.ts +99 -0
- package/src/utils/errors.ts +116 -0
- package/src/utils/interactive.ts +91 -0
- package/src/utils/list-defaults.ts +74 -0
- package/src/utils/output.ts +190 -0
- package/src/utils/progress.ts +320 -0
- package/src/utils/spinner.ts +22 -0
- package/tests/IMPLEMENTATION_STATUS.md +258 -0
- package/tests/PTY_SETUP.md +118 -0
- package/tests/PTY_TESTING_GUIDE.md +507 -0
- package/tests/README.md +244 -0
- package/tests/fixtures/api-responses/campaigns.json +34 -0
- package/tests/fixtures/test-config.json +13 -0
- package/tests/helpers/cli-runner.ts +128 -0
- package/tests/helpers/mock-server.ts +301 -0
- package/tests/helpers/pty-runner.ts +181 -0
- package/tests/integration/campaigns-real-api.test.ts +196 -0
- package/tests/integration/setup-integration.ts +50 -0
- package/tests/pty/campaigns.test.ts +241 -0
- package/tests/setup.ts +34 -0
- package/tsconfig.json +15 -0
- 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
|
+
|