@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,227 @@
|
|
|
1
|
+
# Account Reports & Overview
|
|
2
|
+
|
|
3
|
+
View account-level analytics, usage metrics, and aggregate performance across all campaigns.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Account reports provide:
|
|
8
|
+
- Overall account performance metrics
|
|
9
|
+
- Usage and quota tracking
|
|
10
|
+
- Historical trends across all campaigns
|
|
11
|
+
- List health and growth metrics
|
|
12
|
+
- Sender reputation indicators
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
### View Account Report
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
$ cakemail reports account
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Output:**
|
|
23
|
+
```
|
|
24
|
+
=== Account Overview ===
|
|
25
|
+
Account ID: 456
|
|
26
|
+
Account Name: My Company
|
|
27
|
+
Plan: Professional
|
|
28
|
+
|
|
29
|
+
=== Usage ===
|
|
30
|
+
Contacts: 6,789 / 10,000 (67.9%)
|
|
31
|
+
Emails Sent This Month: 45,678 / 100,000 (45.7%)
|
|
32
|
+
|
|
33
|
+
=== Campaign Performance (Last 30 Days) ===
|
|
34
|
+
Campaigns Sent: 12
|
|
35
|
+
Total Recipients: 142,567
|
|
36
|
+
Average Open Rate: 24.3%
|
|
37
|
+
Average Click Rate: 3.8%
|
|
38
|
+
|
|
39
|
+
=== List Health ===
|
|
40
|
+
Total Lists: 5
|
|
41
|
+
Total Contacts: 6,789
|
|
42
|
+
Active Subscribers: 6,234 (91.8%)
|
|
43
|
+
Unsubscribed: 412 (6.1%)
|
|
44
|
+
Bounced: 143 (2.1%)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Account Metrics
|
|
48
|
+
|
|
49
|
+
### Usage Metrics
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Check quota usage
|
|
53
|
+
$ cakemail reports account -f json | jq '{
|
|
54
|
+
contact_limit: .contact_limit,
|
|
55
|
+
contacts_used: .contacts_used,
|
|
56
|
+
contact_usage_pct: (.contacts_used / .contact_limit * 100 | round),
|
|
57
|
+
email_limit: .email_limit,
|
|
58
|
+
emails_sent: .emails_sent_this_month,
|
|
59
|
+
email_usage_pct: (.emails_sent_this_month / .email_limit * 100 | round)
|
|
60
|
+
}'
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Campaign Aggregate Metrics
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Get overall performance
|
|
67
|
+
$ cakemail reports account -f json | jq '{
|
|
68
|
+
total_campaigns: .campaigns_sent_30d,
|
|
69
|
+
avg_open_rate: .avg_open_rate_30d,
|
|
70
|
+
avg_click_rate: .avg_click_rate_30d,
|
|
71
|
+
avg_delivery_rate: .avg_delivery_rate_30d
|
|
72
|
+
}'
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## List Health Dashboard
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
#!/bin/bash
|
|
79
|
+
# list-health-dashboard.sh
|
|
80
|
+
|
|
81
|
+
echo "=== List Health Dashboard ==="
|
|
82
|
+
echo ""
|
|
83
|
+
|
|
84
|
+
# Get all lists
|
|
85
|
+
LISTS=$(cakemail lists list -f json | jq -r '.data[].id')
|
|
86
|
+
|
|
87
|
+
TOTAL_CONTACTS=0
|
|
88
|
+
TOTAL_ACTIVE=0
|
|
89
|
+
TOTAL_UNSUB=0
|
|
90
|
+
TOTAL_BOUNCED=0
|
|
91
|
+
|
|
92
|
+
echo "List ID | Name | Total | Active | Unsub | Bounce"
|
|
93
|
+
echo "--------|-----------------|-------|--------|-------|--------"
|
|
94
|
+
|
|
95
|
+
for LIST_ID in $LISTS; do
|
|
96
|
+
LIST=$(cakemail lists get $LIST_ID -f json)
|
|
97
|
+
|
|
98
|
+
NAME=$(echo "$LIST" | jq -r '.name' | cut -c1-15)
|
|
99
|
+
TOTAL=$(echo "$LIST" | jq -r '.contacts_count')
|
|
100
|
+
ACTIVE=$(echo "$LIST" | jq -r '.active_contacts')
|
|
101
|
+
UNSUB=$(echo "$LIST" | jq -r '.unsubscribed')
|
|
102
|
+
BOUNCE=$(echo "$LIST" | jq -r '.bounced')
|
|
103
|
+
|
|
104
|
+
printf "%-7s | %-15s | %5d | %6d | %5d | %6d\n" \
|
|
105
|
+
"$LIST_ID" "$NAME" $TOTAL $ACTIVE $UNSUB $BOUNCE
|
|
106
|
+
|
|
107
|
+
TOTAL_CONTACTS=$((TOTAL_CONTACTS + TOTAL))
|
|
108
|
+
TOTAL_ACTIVE=$((TOTAL_ACTIVE + ACTIVE))
|
|
109
|
+
TOTAL_UNSUB=$((TOTAL_UNSUB + UNSUB))
|
|
110
|
+
TOTAL_BOUNCED=$((TOTAL_BOUNCED + BOUNCE))
|
|
111
|
+
done
|
|
112
|
+
|
|
113
|
+
echo "--------|-----------------|-------|--------|-------|--------"
|
|
114
|
+
printf "%-7s | %-15s | %5d | %6d | %5d | %6d\n" \
|
|
115
|
+
"TOTAL" "All Lists" $TOTAL_CONTACTS $TOTAL_ACTIVE $TOTAL_UNSUB $TOTAL_BOUNCED
|
|
116
|
+
|
|
117
|
+
echo ""
|
|
118
|
+
|
|
119
|
+
# Calculate health percentage
|
|
120
|
+
HEALTH=$((TOTAL_ACTIVE * 100 / TOTAL_CONTACTS))
|
|
121
|
+
echo "Overall List Health: $HEALTH%"
|
|
122
|
+
|
|
123
|
+
if [ $HEALTH -ge 90 ]; then
|
|
124
|
+
echo " ✅ Excellent"
|
|
125
|
+
elif [ $HEALTH -ge 80 ]; then
|
|
126
|
+
echo " ✓ Good"
|
|
127
|
+
elif [ $HEALTH -ge 70 ]; then
|
|
128
|
+
echo " ⚠️ Fair - Consider cleanup"
|
|
129
|
+
else
|
|
130
|
+
echo " ❌ Poor - Clean lists immediately"
|
|
131
|
+
fi
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Performance Trends
|
|
135
|
+
|
|
136
|
+
### 30-Day Campaign Summary
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
#!/bin/bash
|
|
140
|
+
# 30day-summary.sh
|
|
141
|
+
|
|
142
|
+
THIRTY_DAYS_AGO=$(date -d "30 days ago" +%Y-%m-%d)
|
|
143
|
+
|
|
144
|
+
echo "=== 30-Day Campaign Summary ==="
|
|
145
|
+
echo ""
|
|
146
|
+
|
|
147
|
+
# Get campaigns from last 30 days
|
|
148
|
+
CAMPAIGNS=$(cakemail campaigns list \
|
|
149
|
+
--filter "status==sent;delivered_at>=$THIRTY_DAYS_AGO" \
|
|
150
|
+
-f json | jq -r '.data[].id')
|
|
151
|
+
|
|
152
|
+
COUNT=0
|
|
153
|
+
TOTAL_RECIPIENTS=0
|
|
154
|
+
TOTAL_OPENS=0
|
|
155
|
+
TOTAL_CLICKS=0
|
|
156
|
+
|
|
157
|
+
for ID in $CAMPAIGNS; do
|
|
158
|
+
REPORT=$(cakemail reports campaign $ID -f json 2>/dev/null)
|
|
159
|
+
|
|
160
|
+
if [ -n "$REPORT" ]; then
|
|
161
|
+
RECIPIENTS=$(echo "$REPORT" | jq -r '.total_recipients')
|
|
162
|
+
OPENS=$(echo "$REPORT" | jq -r '.unique_opens')
|
|
163
|
+
CLICKS=$(echo "$REPORT" | jq -r '.unique_clicks')
|
|
164
|
+
|
|
165
|
+
COUNT=$((COUNT + 1))
|
|
166
|
+
TOTAL_RECIPIENTS=$((TOTAL_RECIPIENTS + RECIPIENTS))
|
|
167
|
+
TOTAL_OPENS=$((TOTAL_OPENS + OPENS))
|
|
168
|
+
TOTAL_CLICKS=$((TOTAL_CLICKS + CLICKS))
|
|
169
|
+
fi
|
|
170
|
+
done
|
|
171
|
+
|
|
172
|
+
if [ $COUNT -gt 0 ]; then
|
|
173
|
+
AVG_OPEN=$((TOTAL_OPENS * 100 / TOTAL_RECIPIENTS))
|
|
174
|
+
AVG_CLICK=$((TOTAL_CLICKS * 100 / TOTAL_RECIPIENTS))
|
|
175
|
+
|
|
176
|
+
echo "Campaigns Sent: $COUNT"
|
|
177
|
+
echo "Total Recipients: $TOTAL_RECIPIENTS"
|
|
178
|
+
echo "Total Opens: $TOTAL_OPENS"
|
|
179
|
+
echo "Total Clicks: $TOTAL_CLICKS"
|
|
180
|
+
echo ""
|
|
181
|
+
echo "Average Open Rate: $AVG_OPEN%"
|
|
182
|
+
echo "Average Click Rate: $AVG_CLICK%"
|
|
183
|
+
else
|
|
184
|
+
echo "No campaigns sent in last 30 days"
|
|
185
|
+
fi
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Growth Tracking
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
#!/bin/bash
|
|
192
|
+
# track-growth.sh
|
|
193
|
+
|
|
194
|
+
LOG_FILE="account-growth.log"
|
|
195
|
+
|
|
196
|
+
# Log current state
|
|
197
|
+
DATE=$(date +%Y-%m-%d)
|
|
198
|
+
ACCOUNT=$(cakemail reports account -f json)
|
|
199
|
+
|
|
200
|
+
CONTACTS=$(echo "$ACCOUNT" | jq -r '.contacts_used')
|
|
201
|
+
CAMPAIGNS=$(echo "$ACCOUNT" | jq -r '.campaigns_sent_30d')
|
|
202
|
+
|
|
203
|
+
echo "$DATE,$CONTACTS,$CAMPAIGNS" >> $LOG_FILE
|
|
204
|
+
|
|
205
|
+
# Show recent growth
|
|
206
|
+
echo "=== Recent Growth ==="
|
|
207
|
+
tail -7 $LOG_FILE | column -t -s','
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Best Practices
|
|
211
|
+
|
|
212
|
+
1. **Monitor Usage Regularly**
|
|
213
|
+
- Check quota usage weekly
|
|
214
|
+
- Plan upgrades before limits
|
|
215
|
+
|
|
216
|
+
2. **Track List Health**
|
|
217
|
+
- Review monthly
|
|
218
|
+
- Clean inactive subscribers
|
|
219
|
+
|
|
220
|
+
3. **Benchmark Performance**
|
|
221
|
+
- Compare to industry standards
|
|
222
|
+
- Track improvements over time
|
|
223
|
+
|
|
224
|
+
4. **Schedule Reports**
|
|
225
|
+
- Weekly dashboards
|
|
226
|
+
- Monthly executive summaries
|
|
227
|
+
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# Webhooks Integration
|
|
2
|
+
|
|
3
|
+
Receive real-time notifications about email events via webhooks for seamless integration with your applications.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Webhooks allow you to:
|
|
8
|
+
- Receive real-time event notifications
|
|
9
|
+
- Integrate with external systems
|
|
10
|
+
- Automate workflows based on email events
|
|
11
|
+
- Track deliverability in your application
|
|
12
|
+
- Sync contact status changes
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
### Create Webhook
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
$ cakemail webhooks create \
|
|
20
|
+
-u "https://api.yourapp.com/webhooks/cakemail" \
|
|
21
|
+
-e "email.sent,email.opened,email.clicked" \
|
|
22
|
+
-n "Production Webhook"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Output:**
|
|
26
|
+
```
|
|
27
|
+
✓ Webhook created successfully
|
|
28
|
+
|
|
29
|
+
ID: 123
|
|
30
|
+
URL: https://api.yourapp.com/webhooks/cakemail
|
|
31
|
+
Events: email.sent, email.opened, email.clicked
|
|
32
|
+
Status: active
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Available Events
|
|
36
|
+
|
|
37
|
+
### Email Events
|
|
38
|
+
|
|
39
|
+
- `email.sent` - Email successfully delivered
|
|
40
|
+
- `email.opened` - Recipient opened email
|
|
41
|
+
- `email.clicked` - Recipient clicked link
|
|
42
|
+
- `email.bounced` - Email bounced
|
|
43
|
+
- `email.unsubscribed` - Recipient unsubscribed
|
|
44
|
+
- `email.spam_complaint` - Marked as spam
|
|
45
|
+
|
|
46
|
+
### Campaign Events
|
|
47
|
+
|
|
48
|
+
- `campaign.sent` - Campaign completed sending
|
|
49
|
+
- `campaign.scheduled` - Campaign scheduled
|
|
50
|
+
- `campaign.cancelled` - Campaign cancelled
|
|
51
|
+
|
|
52
|
+
## Webhook Payload Examples
|
|
53
|
+
|
|
54
|
+
### Email Sent Event
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"event": "email.sent",
|
|
59
|
+
"timestamp": "2024-03-15T10:30:00Z",
|
|
60
|
+
"data": {
|
|
61
|
+
"campaign_id": 790,
|
|
62
|
+
"contact_id": 501,
|
|
63
|
+
"email": "user@example.com",
|
|
64
|
+
"message_id": "msg_abc123"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Email Opened Event
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"event": "email.opened",
|
|
74
|
+
"timestamp": "2024-03-15T11:45:00Z",
|
|
75
|
+
"data": {
|
|
76
|
+
"campaign_id": 790,
|
|
77
|
+
"contact_id": 501,
|
|
78
|
+
"email": "user@example.com",
|
|
79
|
+
"user_agent": "Mozilla/5.0...",
|
|
80
|
+
"ip_address": "192.168.1.1"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Integration Examples
|
|
86
|
+
|
|
87
|
+
### Node.js/Express
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
const express = require('express');
|
|
91
|
+
const app = express();
|
|
92
|
+
|
|
93
|
+
app.post('/webhooks/cakemail', express.json(), (req, res) => {
|
|
94
|
+
const { event, timestamp, data } = req.body;
|
|
95
|
+
|
|
96
|
+
switch(event) {
|
|
97
|
+
case 'email.opened':
|
|
98
|
+
console.log(`Email opened: ${data.email}`);
|
|
99
|
+
// Update your database
|
|
100
|
+
break;
|
|
101
|
+
|
|
102
|
+
case 'email.clicked':
|
|
103
|
+
console.log(`Link clicked: ${data.email}`);
|
|
104
|
+
// Track engagement
|
|
105
|
+
break;
|
|
106
|
+
|
|
107
|
+
case 'email.bounced':
|
|
108
|
+
console.log(`Email bounced: ${data.email}`);
|
|
109
|
+
// Remove from list
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
res.status(200).send('OK');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
app.listen(3000);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Python/Flask
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from flask import Flask, request
|
|
123
|
+
import json
|
|
124
|
+
|
|
125
|
+
app = Flask(__name__)
|
|
126
|
+
|
|
127
|
+
@app.route('/webhooks/cakemail', methods=['POST'])
|
|
128
|
+
def cakemail_webhook():
|
|
129
|
+
data = request.json
|
|
130
|
+
event = data.get('event')
|
|
131
|
+
|
|
132
|
+
if event == 'email.opened':
|
|
133
|
+
email = data['data']['email']
|
|
134
|
+
# Update database
|
|
135
|
+
print(f"Email opened: {email}")
|
|
136
|
+
|
|
137
|
+
elif event == 'email.clicked':
|
|
138
|
+
email = data['data']['email']
|
|
139
|
+
# Track engagement
|
|
140
|
+
print(f"Link clicked: {email}")
|
|
141
|
+
|
|
142
|
+
return '', 200
|
|
143
|
+
|
|
144
|
+
if __name__ == '__main__':
|
|
145
|
+
app.run(port=5000)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### PHP
|
|
149
|
+
|
|
150
|
+
```php
|
|
151
|
+
<?php
|
|
152
|
+
$payload = file_get_contents('php://input');
|
|
153
|
+
$data = json_decode($payload, true);
|
|
154
|
+
|
|
155
|
+
$event = $data['event'];
|
|
156
|
+
$eventData = $data['data'];
|
|
157
|
+
|
|
158
|
+
switch($event) {
|
|
159
|
+
case 'email.opened':
|
|
160
|
+
$email = $eventData['email'];
|
|
161
|
+
// Update database
|
|
162
|
+
error_log("Email opened: $email");
|
|
163
|
+
break;
|
|
164
|
+
|
|
165
|
+
case 'email.clicked':
|
|
166
|
+
$email = $eventData['email'];
|
|
167
|
+
// Track engagement
|
|
168
|
+
error_log("Link clicked: $email");
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
http_response_code(200);
|
|
173
|
+
?>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Webhook Management
|
|
177
|
+
|
|
178
|
+
### List Webhooks
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
$ cakemail webhooks list
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Update Webhook
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
$ cakemail webhooks update 123 \
|
|
188
|
+
-e "email.sent,email.opened,email.clicked,email.bounced"
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Test Webhook
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
$ cakemail webhooks test 123
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Delete Webhook
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
$ cakemail webhooks delete 123 --force
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Security
|
|
204
|
+
|
|
205
|
+
### Verify Webhook Signature
|
|
206
|
+
|
|
207
|
+
Cakemail signs webhook payloads with HMAC-SHA256:
|
|
208
|
+
|
|
209
|
+
```javascript
|
|
210
|
+
const crypto = require('crypto');
|
|
211
|
+
|
|
212
|
+
function verifyWebhook(payload, signature, secret) {
|
|
213
|
+
const hmac = crypto
|
|
214
|
+
.createHmac('sha256', secret)
|
|
215
|
+
.update(payload)
|
|
216
|
+
.digest('hex');
|
|
217
|
+
|
|
218
|
+
return crypto.timingSafeEqual(
|
|
219
|
+
Buffer.from(signature),
|
|
220
|
+
Buffer.from(hmac)
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
app.post('/webhooks/cakemail', (req, res) => {
|
|
225
|
+
const signature = req.headers['x-cakemail-signature'];
|
|
226
|
+
const payload = JSON.stringify(req.body);
|
|
227
|
+
|
|
228
|
+
if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) {
|
|
229
|
+
return res.status(401).send('Invalid signature');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Process webhook
|
|
233
|
+
res.status(200).send('OK');
|
|
234
|
+
});
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Best Practices
|
|
238
|
+
|
|
239
|
+
1. **Return 200 Quickly** - Process async
|
|
240
|
+
2. **Verify Signatures** - Security
|
|
241
|
+
3. **Handle Retries** - Idempotent processing
|
|
242
|
+
4. **Log Events** - Debugging
|
|
243
|
+
5. **Monitor Failures** - Alert on errors
|
|
244
|
+
|
|
245
|
+
## Troubleshooting
|
|
246
|
+
|
|
247
|
+
### Webhook Not Receiving Events
|
|
248
|
+
|
|
249
|
+
- Verify URL is publicly accessible
|
|
250
|
+
- Check firewall/security rules
|
|
251
|
+
- Test with `cakemail webhooks test`
|
|
252
|
+
- Check application logs
|
|
253
|
+
|
|
254
|
+
### Missing Events
|
|
255
|
+
|
|
256
|
+
- Verify events subscribed
|
|
257
|
+
- Check application response time
|
|
258
|
+
- Monitor webhook status
|
|
259
|
+
|