@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,709 @@
|
|
|
1
|
+
# Campaign Lifecycle
|
|
2
|
+
|
|
3
|
+
Understand and manage campaigns through every stage from creation to completion.
|
|
4
|
+
|
|
5
|
+
## Lifecycle Overview
|
|
6
|
+
|
|
7
|
+
Campaigns move through distinct states:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
draft → scheduled → sending → sent → archived
|
|
11
|
+
↓ ↓ ↓
|
|
12
|
+
delete unschedule suspend/cancel
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Campaign States
|
|
16
|
+
|
|
17
|
+
### Draft
|
|
18
|
+
|
|
19
|
+
**Description:** Newly created, not yet scheduled
|
|
20
|
+
|
|
21
|
+
**Available Actions:**
|
|
22
|
+
- Edit content, subject, list, sender
|
|
23
|
+
- Send test emails
|
|
24
|
+
- Schedule for delivery
|
|
25
|
+
- Delete
|
|
26
|
+
|
|
27
|
+
**Commands:**
|
|
28
|
+
```bash
|
|
29
|
+
# Update draft
|
|
30
|
+
$ cakemail campaigns update 790 --subject "New Subject"
|
|
31
|
+
|
|
32
|
+
# Send test
|
|
33
|
+
$ cakemail campaigns test 790 -e test@example.com
|
|
34
|
+
|
|
35
|
+
# Schedule
|
|
36
|
+
$ cakemail campaigns schedule 790
|
|
37
|
+
|
|
38
|
+
# Delete if not needed
|
|
39
|
+
$ cakemail campaigns delete 790 --force
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Scheduled
|
|
43
|
+
|
|
44
|
+
**Description:** Queued for future delivery
|
|
45
|
+
|
|
46
|
+
**Available Actions:**
|
|
47
|
+
- Reschedule to different time
|
|
48
|
+
- Unschedule (return to draft)
|
|
49
|
+
- Send test emails
|
|
50
|
+
- Cancel
|
|
51
|
+
|
|
52
|
+
**Commands:**
|
|
53
|
+
```bash
|
|
54
|
+
# Reschedule
|
|
55
|
+
$ cakemail campaigns reschedule 790 --when "2024-03-25 10:00:00"
|
|
56
|
+
|
|
57
|
+
# Unschedule (back to draft)
|
|
58
|
+
$ cakemail campaigns unschedule 790
|
|
59
|
+
|
|
60
|
+
# Cancel
|
|
61
|
+
$ cakemail campaigns cancel 790
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Sending
|
|
65
|
+
|
|
66
|
+
**Description:** Currently being sent to recipients
|
|
67
|
+
|
|
68
|
+
**Available Actions:**
|
|
69
|
+
- Suspend (pause sending)
|
|
70
|
+
- View progress
|
|
71
|
+
- Monitor statistics
|
|
72
|
+
|
|
73
|
+
**Commands:**
|
|
74
|
+
```bash
|
|
75
|
+
# Suspend sending
|
|
76
|
+
$ cakemail campaigns suspend 790
|
|
77
|
+
|
|
78
|
+
# Check progress
|
|
79
|
+
$ cakemail campaigns get 790 -f json | jq '{status, sent_count, total_recipients}'
|
|
80
|
+
|
|
81
|
+
# View real-time stats
|
|
82
|
+
$ cakemail reports campaign 790
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Sent
|
|
86
|
+
|
|
87
|
+
**Description:** Completed successfully
|
|
88
|
+
|
|
89
|
+
**Available Actions:**
|
|
90
|
+
- View analytics
|
|
91
|
+
- Archive
|
|
92
|
+
- Delete (removes from list)
|
|
93
|
+
|
|
94
|
+
**Commands:**
|
|
95
|
+
```bash
|
|
96
|
+
# View analytics
|
|
97
|
+
$ cakemail reports campaign 790
|
|
98
|
+
|
|
99
|
+
# View link clicks
|
|
100
|
+
$ cakemail reports campaign-links 790
|
|
101
|
+
|
|
102
|
+
# Archive
|
|
103
|
+
$ cakemail campaigns archive 790
|
|
104
|
+
|
|
105
|
+
# Delete
|
|
106
|
+
$ cakemail campaigns delete 790 --force
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Suspended
|
|
110
|
+
|
|
111
|
+
**Description:** Paused during sending
|
|
112
|
+
|
|
113
|
+
**Available Actions:**
|
|
114
|
+
- Resume sending
|
|
115
|
+
- Cancel (stops permanently)
|
|
116
|
+
- View partial statistics
|
|
117
|
+
|
|
118
|
+
**Commands:**
|
|
119
|
+
```bash
|
|
120
|
+
# Resume
|
|
121
|
+
$ cakemail campaigns resume 790
|
|
122
|
+
|
|
123
|
+
# Cancel permanently
|
|
124
|
+
$ cakemail campaigns cancel 790
|
|
125
|
+
|
|
126
|
+
# Check stats
|
|
127
|
+
$ cakemail reports campaign 790
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Cancelled
|
|
131
|
+
|
|
132
|
+
**Description:** Cancelled before/during send
|
|
133
|
+
|
|
134
|
+
**Available Actions:**
|
|
135
|
+
- View partial analytics
|
|
136
|
+
- Archive
|
|
137
|
+
- Delete
|
|
138
|
+
|
|
139
|
+
**Commands:**
|
|
140
|
+
```bash
|
|
141
|
+
# View what was sent
|
|
142
|
+
$ cakemail reports campaign 790
|
|
143
|
+
|
|
144
|
+
# Archive
|
|
145
|
+
$ cakemail campaigns archive 790
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Archived
|
|
149
|
+
|
|
150
|
+
**Description:** Hidden from default views
|
|
151
|
+
|
|
152
|
+
**Available Actions:**
|
|
153
|
+
- Unarchive (restore to view)
|
|
154
|
+
- View analytics
|
|
155
|
+
- Delete permanently
|
|
156
|
+
|
|
157
|
+
**Commands:**
|
|
158
|
+
```bash
|
|
159
|
+
# Unarchive
|
|
160
|
+
$ cakemail campaigns unarchive 790
|
|
161
|
+
|
|
162
|
+
# View
|
|
163
|
+
$ cakemail campaigns get 790
|
|
164
|
+
|
|
165
|
+
# Delete
|
|
166
|
+
$ cakemail campaigns delete 790 --force
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Managing Active Campaigns
|
|
170
|
+
|
|
171
|
+
### Suspending a Campaign
|
|
172
|
+
|
|
173
|
+
Pause campaign mid-send:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
$ cakemail campaigns suspend 790
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Output:**
|
|
180
|
+
```
|
|
181
|
+
✓ Campaign 790 suspended
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**When to suspend:**
|
|
185
|
+
- Content error discovered
|
|
186
|
+
- Wrong list selected
|
|
187
|
+
- Need to make urgent changes
|
|
188
|
+
- Technical issue with website/links
|
|
189
|
+
|
|
190
|
+
**What happens:**
|
|
191
|
+
- Sending stops immediately
|
|
192
|
+
- Emails already sent remain sent
|
|
193
|
+
- Remaining recipients not contacted
|
|
194
|
+
- Can resume or cancel later
|
|
195
|
+
|
|
196
|
+
### Resuming a Campaign
|
|
197
|
+
|
|
198
|
+
Continue suspended campaign:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
$ cakemail campaigns resume 790
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Output:**
|
|
205
|
+
```
|
|
206
|
+
✓ Campaign 790 resumed
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Considerations:**
|
|
210
|
+
- Resumes from where it stopped
|
|
211
|
+
- Already-sent contacts not re-contacted
|
|
212
|
+
- Check time delay impact on results
|
|
213
|
+
|
|
214
|
+
### Cancelling a Campaign
|
|
215
|
+
|
|
216
|
+
Permanently stop campaign:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
$ cakemail campaigns cancel 790
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Output:**
|
|
223
|
+
```
|
|
224
|
+
⚠ Cancel campaign 790?
|
|
225
|
+
|
|
226
|
+
The following will happen:
|
|
227
|
+
• Campaign will be permanently cancelled
|
|
228
|
+
• Remaining recipients will not receive email
|
|
229
|
+
• Partial analytics available
|
|
230
|
+
|
|
231
|
+
Type 'yes' to confirm: yes
|
|
232
|
+
|
|
233
|
+
✓ Campaign 790 cancelled
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**When to cancel:**
|
|
237
|
+
- Major error in content
|
|
238
|
+
- Wrong audience targeted
|
|
239
|
+
- Business reason (product recall, etc.)
|
|
240
|
+
- Regulatory/legal requirement
|
|
241
|
+
|
|
242
|
+
## Archiving Campaigns
|
|
243
|
+
|
|
244
|
+
### Archive Completed Campaigns
|
|
245
|
+
|
|
246
|
+
Remove from active view:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
$ cakemail campaigns archive 790
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Output:**
|
|
253
|
+
```
|
|
254
|
+
✓ Campaign 790 archived
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**Benefits:**
|
|
258
|
+
- Cleaner campaign list
|
|
259
|
+
- Organized historical data
|
|
260
|
+
- Still accessible for analytics
|
|
261
|
+
- Can be unarchived if needed
|
|
262
|
+
|
|
263
|
+
### Bulk Archive
|
|
264
|
+
|
|
265
|
+
Archive multiple campaigns:
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
#!/bin/bash
|
|
269
|
+
# archive-old-campaigns.sh
|
|
270
|
+
|
|
271
|
+
# Archive all campaigns from Q1 2024
|
|
272
|
+
CAMPAIGNS=$(cakemail campaigns list \
|
|
273
|
+
--filter "status==sent;delivered_at>=2024-01-01;delivered_at<2024-04-01" \
|
|
274
|
+
-f json | jq -r '.data[].id')
|
|
275
|
+
|
|
276
|
+
for ID in $CAMPAIGNS; do
|
|
277
|
+
echo "Archiving campaign $ID..."
|
|
278
|
+
cakemail campaigns archive $ID
|
|
279
|
+
done
|
|
280
|
+
|
|
281
|
+
echo "Archived $(echo "$CAMPAIGNS" | wc -l) campaigns"
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Archive by Age
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
#!/bin/bash
|
|
288
|
+
# archive-by-age.sh
|
|
289
|
+
|
|
290
|
+
# Archive campaigns older than 90 days
|
|
291
|
+
CUTOFF_DATE=$(date -d "90 days ago" +%Y-%m-%d)
|
|
292
|
+
|
|
293
|
+
CAMPAIGNS=$(cakemail campaigns list \
|
|
294
|
+
--filter "status==sent;delivered_at<$CUTOFF_DATE" \
|
|
295
|
+
-f json | jq -r '.data[].id')
|
|
296
|
+
|
|
297
|
+
for ID in $CAMPAIGNS; do
|
|
298
|
+
NAME=$(cakemail campaigns get $ID -f json | jq -r '.name')
|
|
299
|
+
echo "Archiving: $NAME (ID: $ID)"
|
|
300
|
+
cakemail campaigns archive $ID
|
|
301
|
+
done
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Unarchive Campaigns
|
|
305
|
+
|
|
306
|
+
Restore archived campaign to active view:
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
$ cakemail campaigns unarchive 790
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**Output:**
|
|
313
|
+
```
|
|
314
|
+
✓ Campaign 790 unarchived
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Monitoring Campaigns
|
|
318
|
+
|
|
319
|
+
### Real-Time Status Check
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
#!/bin/bash
|
|
323
|
+
# monitor-campaign.sh
|
|
324
|
+
|
|
325
|
+
CAMPAIGN_ID=$1
|
|
326
|
+
INTERVAL=5 # seconds
|
|
327
|
+
|
|
328
|
+
while true; do
|
|
329
|
+
clear
|
|
330
|
+
echo "=== Campaign $CAMPAIGN_ID Status ==="
|
|
331
|
+
echo ""
|
|
332
|
+
|
|
333
|
+
STATUS=$(cakemail campaigns get $CAMPAIGN_ID -f json)
|
|
334
|
+
|
|
335
|
+
echo "Status: $(echo "$STATUS" | jq -r '.status')"
|
|
336
|
+
echo "Name: $(echo "$STATUS" | jq -r '.name')"
|
|
337
|
+
echo ""
|
|
338
|
+
|
|
339
|
+
# If sending, show progress
|
|
340
|
+
if [ "$(echo "$STATUS" | jq -r '.status')" == "sending" ]; then
|
|
341
|
+
SENT=$(echo "$STATUS" | jq -r '.sent_count // 0')
|
|
342
|
+
TOTAL=$(echo "$STATUS" | jq -r '.total_recipients // 0')
|
|
343
|
+
PERCENT=$(echo "scale=1; $SENT * 100 / $TOTAL" | bc)
|
|
344
|
+
|
|
345
|
+
echo "Progress: $SENT / $TOTAL ($PERCENT%)"
|
|
346
|
+
echo ""
|
|
347
|
+
|
|
348
|
+
# Get stats
|
|
349
|
+
STATS=$(cakemail reports campaign $CAMPAIGN_ID -f json)
|
|
350
|
+
echo "Delivered: $(echo "$STATS" | jq -r '.delivered // 0')"
|
|
351
|
+
echo "Opened: $(echo "$STATS" | jq -r '.unique_opens // 0')"
|
|
352
|
+
echo "Clicked: $(echo "$STATS" | jq -r '.unique_clicks // 0')"
|
|
353
|
+
fi
|
|
354
|
+
|
|
355
|
+
echo ""
|
|
356
|
+
echo "Press Ctrl+C to stop monitoring"
|
|
357
|
+
sleep $INTERVAL
|
|
358
|
+
done
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Dashboard View
|
|
362
|
+
|
|
363
|
+
```bash
|
|
364
|
+
#!/bin/bash
|
|
365
|
+
# campaign-dashboard.sh
|
|
366
|
+
|
|
367
|
+
echo "=== Campaign Dashboard ==="
|
|
368
|
+
echo ""
|
|
369
|
+
|
|
370
|
+
# Scheduled
|
|
371
|
+
SCHEDULED=$(cakemail campaigns list --filter "status==scheduled" -f json | jq '.count')
|
|
372
|
+
echo "Scheduled: $SCHEDULED"
|
|
373
|
+
|
|
374
|
+
# Sending
|
|
375
|
+
SENDING=$(cakemail campaigns list --filter "status==sending" -f json | jq '.count')
|
|
376
|
+
echo "Sending: $SENDING"
|
|
377
|
+
|
|
378
|
+
# Sent today
|
|
379
|
+
TODAY=$(date +%Y-%m-%d)
|
|
380
|
+
SENT_TODAY=$(cakemail campaigns list \
|
|
381
|
+
--filter "status==sent;delivered_at>=$TODAY" \
|
|
382
|
+
-f json | jq '.count')
|
|
383
|
+
echo "Sent Today: $SENT_TODAY"
|
|
384
|
+
|
|
385
|
+
# Drafts
|
|
386
|
+
DRAFTS=$(cakemail campaigns list --filter "status==draft" -f json | jq '.count')
|
|
387
|
+
echo "Drafts: $DRAFTS"
|
|
388
|
+
|
|
389
|
+
echo ""
|
|
390
|
+
|
|
391
|
+
# Show active campaigns
|
|
392
|
+
echo "=== Active Campaigns ==="
|
|
393
|
+
cakemail campaigns list --filter "status==sending" -f compact
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## Lifecycle Workflows
|
|
397
|
+
|
|
398
|
+
### Workflow 1: Emergency Stop
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
#!/bin/bash
|
|
402
|
+
# emergency-stop.sh
|
|
403
|
+
|
|
404
|
+
CAMPAIGN_ID=$1
|
|
405
|
+
|
|
406
|
+
if [ -z "$CAMPAIGN_ID" ]; then
|
|
407
|
+
echo "Usage: $0 <campaign-id>"
|
|
408
|
+
exit 1
|
|
409
|
+
fi
|
|
410
|
+
|
|
411
|
+
echo "⚠️ EMERGENCY STOP for Campaign $CAMPAIGN_ID"
|
|
412
|
+
echo ""
|
|
413
|
+
|
|
414
|
+
# Check current status
|
|
415
|
+
STATUS=$(cakemail campaigns get $CAMPAIGN_ID -f json | jq -r '.status')
|
|
416
|
+
echo "Current status: $STATUS"
|
|
417
|
+
|
|
418
|
+
case $STATUS in
|
|
419
|
+
"scheduled")
|
|
420
|
+
echo "Unscheduling..."
|
|
421
|
+
cakemail campaigns unschedule $CAMPAIGN_ID
|
|
422
|
+
;;
|
|
423
|
+
"sending")
|
|
424
|
+
echo "Suspending..."
|
|
425
|
+
cakemail campaigns suspend $CAMPAIGN_ID
|
|
426
|
+
;;
|
|
427
|
+
*)
|
|
428
|
+
echo "Campaign is $STATUS - no action needed"
|
|
429
|
+
;;
|
|
430
|
+
esac
|
|
431
|
+
|
|
432
|
+
echo ""
|
|
433
|
+
echo "✅ Emergency stop complete"
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Workflow 2: Scheduled Maintenance
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
#!/bin/bash
|
|
440
|
+
# scheduled-maintenance.sh
|
|
441
|
+
|
|
442
|
+
echo "=== Pre-Maintenance: Suspend Active Campaigns ==="
|
|
443
|
+
|
|
444
|
+
# Get all sending campaigns
|
|
445
|
+
SENDING=$(cakemail campaigns list --filter "status==sending" -f json)
|
|
446
|
+
SENDING_IDS=$(echo "$SENDING" | jq -r '.data[].id')
|
|
447
|
+
|
|
448
|
+
# Suspend each
|
|
449
|
+
for ID in $SENDING_IDS; do
|
|
450
|
+
echo "Suspending campaign $ID..."
|
|
451
|
+
cakemail campaigns suspend $ID
|
|
452
|
+
done
|
|
453
|
+
|
|
454
|
+
echo ""
|
|
455
|
+
echo "Suspended $(echo "$SENDING_IDS" | wc -l) campaigns"
|
|
456
|
+
echo "IDs: $SENDING_IDS"
|
|
457
|
+
echo ""
|
|
458
|
+
echo "Save these IDs to resume after maintenance!"
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
Resume after maintenance:
|
|
462
|
+
|
|
463
|
+
```bash
|
|
464
|
+
#!/bin/bash
|
|
465
|
+
# resume-after-maintenance.sh
|
|
466
|
+
|
|
467
|
+
# IDs from previous script
|
|
468
|
+
CAMPAIGN_IDS="790 791 792"
|
|
469
|
+
|
|
470
|
+
echo "=== Post-Maintenance: Resume Campaigns ==="
|
|
471
|
+
|
|
472
|
+
for ID in $CAMPAIGN_IDS; do
|
|
473
|
+
echo "Resuming campaign $ID..."
|
|
474
|
+
cakemail campaigns resume $ID
|
|
475
|
+
done
|
|
476
|
+
|
|
477
|
+
echo ""
|
|
478
|
+
echo "✅ All campaigns resumed"
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### Workflow 3: Quarterly Archival
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
#!/bin/bash
|
|
485
|
+
# quarterly-archive.sh
|
|
486
|
+
|
|
487
|
+
YEAR=$1
|
|
488
|
+
QUARTER=$2
|
|
489
|
+
|
|
490
|
+
if [ -z "$YEAR" ] || [ -z "$QUARTER" ]; then
|
|
491
|
+
echo "Usage: $0 <year> <quarter>"
|
|
492
|
+
echo "Example: $0 2024 1"
|
|
493
|
+
exit 1
|
|
494
|
+
fi
|
|
495
|
+
|
|
496
|
+
# Calculate date range
|
|
497
|
+
case $QUARTER in
|
|
498
|
+
1) START="$YEAR-01-01"; END="$YEAR-03-31" ;;
|
|
499
|
+
2) START="$YEAR-04-01"; END="$YEAR-06-30" ;;
|
|
500
|
+
3) START="$YEAR-07-01"; END="$YEAR-09-30" ;;
|
|
501
|
+
4) START="$YEAR-10-01"; END="$YEAR-12-31" ;;
|
|
502
|
+
*) echo "Invalid quarter"; exit 1 ;;
|
|
503
|
+
esac
|
|
504
|
+
|
|
505
|
+
echo "Archiving Q$QUARTER $YEAR campaigns ($START to $END)..."
|
|
506
|
+
|
|
507
|
+
# Get campaigns
|
|
508
|
+
CAMPAIGNS=$(cakemail campaigns list \
|
|
509
|
+
--filter "status==sent;delivered_at>=$START;delivered_at<=$END" \
|
|
510
|
+
-f json | jq -r '.data[].id')
|
|
511
|
+
|
|
512
|
+
COUNT=0
|
|
513
|
+
for ID in $CAMPAIGNS; do
|
|
514
|
+
cakemail campaigns archive $ID
|
|
515
|
+
((COUNT++))
|
|
516
|
+
done
|
|
517
|
+
|
|
518
|
+
echo ""
|
|
519
|
+
echo "✅ Archived $COUNT campaigns from Q$QUARTER $YEAR"
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### Workflow 4: Campaign Health Check
|
|
523
|
+
|
|
524
|
+
```bash
|
|
525
|
+
#!/bin/bash
|
|
526
|
+
# health-check.sh
|
|
527
|
+
|
|
528
|
+
echo "=== Campaign Health Check ==="
|
|
529
|
+
echo ""
|
|
530
|
+
|
|
531
|
+
# Check for stuck campaigns
|
|
532
|
+
echo "Checking for stuck campaigns..."
|
|
533
|
+
SENDING=$(cakemail campaigns list --filter "status==sending" -f json)
|
|
534
|
+
SENDING_COUNT=$(echo "$SENDING" | jq '.count')
|
|
535
|
+
|
|
536
|
+
if [ "$SENDING_COUNT" -gt 0 ]; then
|
|
537
|
+
echo "$SENDING" | jq -r '.data[] | " ID: \(.id) - Started: \(.sending_started_at // "unknown")"'
|
|
538
|
+
|
|
539
|
+
# Flag campaigns sending > 2 hours
|
|
540
|
+
CUTOFF=$(date -d "2 hours ago" --iso-8601=seconds)
|
|
541
|
+
STUCK=$(echo "$SENDING" | jq --arg cutoff "$CUTOFF" '
|
|
542
|
+
.data[] | select(.sending_started_at < $cutoff)
|
|
543
|
+
')
|
|
544
|
+
|
|
545
|
+
if [ -n "$STUCK" ]; then
|
|
546
|
+
echo ""
|
|
547
|
+
echo "⚠️ Warning: Campaigns sending > 2 hours:"
|
|
548
|
+
echo "$STUCK" | jq -r '" ID: \(.id) - \(.name)"'
|
|
549
|
+
fi
|
|
550
|
+
else
|
|
551
|
+
echo " ✅ No campaigns currently sending"
|
|
552
|
+
fi
|
|
553
|
+
|
|
554
|
+
echo ""
|
|
555
|
+
|
|
556
|
+
# Check for scheduled campaigns in past
|
|
557
|
+
echo "Checking for past-due scheduled campaigns..."
|
|
558
|
+
NOW=$(date --iso-8601=seconds)
|
|
559
|
+
PAST_DUE=$(cakemail campaigns list --filter "status==scheduled" -f json | \
|
|
560
|
+
jq --arg now "$NOW" '.data[] | select(.scheduled_for < $now)')
|
|
561
|
+
|
|
562
|
+
if [ -n "$PAST_DUE" ]; then
|
|
563
|
+
echo "⚠️ Warning: Past-due scheduled campaigns:"
|
|
564
|
+
echo "$PAST_DUE" | jq -r '" ID: \(.id) - Scheduled: \(.scheduled_for)"'
|
|
565
|
+
else
|
|
566
|
+
echo " ✅ No past-due campaigns"
|
|
567
|
+
fi
|
|
568
|
+
|
|
569
|
+
echo ""
|
|
570
|
+
|
|
571
|
+
# Check for old drafts
|
|
572
|
+
echo "Checking for old drafts (> 30 days)..."
|
|
573
|
+
OLD_CUTOFF=$(date -d "30 days ago" +%Y-%m-%d)
|
|
574
|
+
OLD_DRAFTS=$(cakemail campaigns list \
|
|
575
|
+
--filter "status==draft;created_on<$OLD_CUTOFF" \
|
|
576
|
+
-f json | jq '.count')
|
|
577
|
+
|
|
578
|
+
echo " Old drafts: $OLD_DRAFTS"
|
|
579
|
+
|
|
580
|
+
if [ "$OLD_DRAFTS" -gt 0 ]; then
|
|
581
|
+
echo " Consider cleaning up old drafts"
|
|
582
|
+
fi
|
|
583
|
+
|
|
584
|
+
echo ""
|
|
585
|
+
echo "✅ Health check complete"
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
## Best Practices
|
|
589
|
+
|
|
590
|
+
### 1. Monitor Active Campaigns
|
|
591
|
+
|
|
592
|
+
Set up automated monitoring:
|
|
593
|
+
|
|
594
|
+
```bash
|
|
595
|
+
# Add to crontab: every 5 minutes
|
|
596
|
+
*/5 * * * * /path/to/monitor-campaigns.sh >> /var/log/campaign-monitor.log 2>&1
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### 2. Archive Regularly
|
|
600
|
+
|
|
601
|
+
Monthly archival routine:
|
|
602
|
+
|
|
603
|
+
```bash
|
|
604
|
+
# First day of each month
|
|
605
|
+
0 0 1 * * /path/to/monthly-archive.sh
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
### 3. Emergency Procedures
|
|
609
|
+
|
|
610
|
+
Document emergency contacts and procedures:
|
|
611
|
+
|
|
612
|
+
```bash
|
|
613
|
+
#!/bin/bash
|
|
614
|
+
# EMERGENCY.sh
|
|
615
|
+
|
|
616
|
+
echo "=== EMERGENCY CAMPAIGN PROCEDURES ==="
|
|
617
|
+
echo ""
|
|
618
|
+
echo "1. Suspend all sending: ./emergency-stop-all.sh"
|
|
619
|
+
echo "2. Contact: support@cakemail.com"
|
|
620
|
+
echo "3. Escalation: +1-XXX-XXX-XXXX"
|
|
621
|
+
echo ""
|
|
622
|
+
echo "Campaign ID to stop:"
|
|
623
|
+
read CAMPAIGN_ID
|
|
624
|
+
|
|
625
|
+
./emergency-stop.sh $CAMPAIGN_ID
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### 4. Document State Changes
|
|
629
|
+
|
|
630
|
+
Log important actions:
|
|
631
|
+
|
|
632
|
+
```bash
|
|
633
|
+
# Log state changes
|
|
634
|
+
log_action() {
|
|
635
|
+
echo "$(date --iso-8601=seconds) | $1 | $2" >> campaign-actions.log
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
# Usage
|
|
639
|
+
log_action "SUSPEND" "Campaign 790 suspended due to content error"
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
### 5. Review Before Archiving
|
|
643
|
+
|
|
644
|
+
Ensure analytics captured:
|
|
645
|
+
|
|
646
|
+
```bash
|
|
647
|
+
#!/bin/bash
|
|
648
|
+
# safe-archive.sh
|
|
649
|
+
|
|
650
|
+
CAMPAIGN_ID=$1
|
|
651
|
+
|
|
652
|
+
# Get final stats
|
|
653
|
+
STATS=$(cakemail reports campaign $CAMPAIGN_ID -f json)
|
|
654
|
+
|
|
655
|
+
# Save to file
|
|
656
|
+
echo "$STATS" > "campaign-$CAMPAIGN_ID-stats.json"
|
|
657
|
+
|
|
658
|
+
# Now archive
|
|
659
|
+
cakemail campaigns archive $CAMPAIGN_ID
|
|
660
|
+
|
|
661
|
+
echo "Stats saved and campaign archived"
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
## Troubleshooting
|
|
665
|
+
|
|
666
|
+
### Campaign Stuck in "Sending"
|
|
667
|
+
|
|
668
|
+
**Problem:** Campaign status "sending" for extended period
|
|
669
|
+
|
|
670
|
+
**Investigation:**
|
|
671
|
+
```bash
|
|
672
|
+
# Check how long it's been sending
|
|
673
|
+
$ cakemail campaigns get 790 -f json | jq '{status, sending_started_at, sent_count, total_recipients}'
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
**Solutions:**
|
|
677
|
+
- Large lists take time (normal for 10k+ contacts)
|
|
678
|
+
- Contact support if > 4 hours with no progress
|
|
679
|
+
- Check account status for issues
|
|
680
|
+
|
|
681
|
+
### Cannot Suspend Campaign
|
|
682
|
+
|
|
683
|
+
**Error:** "Campaign cannot be suspended"
|
|
684
|
+
|
|
685
|
+
**Possible reasons:**
|
|
686
|
+
- Campaign already completed
|
|
687
|
+
- Campaign not in "sending" status
|
|
688
|
+
- Too close to completion
|
|
689
|
+
|
|
690
|
+
**Check status:**
|
|
691
|
+
```bash
|
|
692
|
+
$ cakemail campaigns get 790 -f json | jq '.status'
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
### Suspended Campaign Won't Resume
|
|
696
|
+
|
|
697
|
+
**Problem:** Resume command fails
|
|
698
|
+
|
|
699
|
+
**Solutions:**
|
|
700
|
+
```bash
|
|
701
|
+
# Check if campaign cancelled
|
|
702
|
+
$ cakemail campaigns get 790 -f json | jq '.status'
|
|
703
|
+
|
|
704
|
+
# If cancelled, cannot resume (create new campaign)
|
|
705
|
+
|
|
706
|
+
# If suspended, try again
|
|
707
|
+
$ cakemail campaigns resume 790
|
|
708
|
+
```
|
|
709
|
+
|