@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.
- 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 +319 -15
- package/audit-formats.js +128 -0
- package/cakemail.rb +20 -0
- package/dist/cli.js +27 -10
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +16 -6
- 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.d.ts.map +1 -1
- package/dist/commands/campaigns.js +103 -8
- package/dist/commands/campaigns.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +63 -4
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/contacts.d.ts.map +1 -1
- package/dist/commands/contacts.js +91 -12
- 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.d.ts +5 -0
- package/dist/commands/interests.d.ts.map +1 -0
- package/dist/commands/interests.js +172 -0
- package/dist/commands/interests.js.map +1 -0
- package/dist/commands/lists.d.ts.map +1 -1
- package/dist/commands/lists.js +6 -8
- package/dist/commands/lists.js.map +1 -1
- package/dist/commands/logs.d.ts +5 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +237 -0
- package/dist/commands/logs.js.map +1 -0
- 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.d.ts.map +1 -1
- package/dist/commands/senders.js +11 -8
- 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.d.ts +5 -0
- package/dist/commands/tags.d.ts.map +1 -0
- package/dist/commands/tags.js +124 -0
- package/dist/commands/tags.js.map +1 -0
- package/dist/commands/templates.js +1 -1
- package/dist/commands/templates.js.map +1 -1
- package/dist/commands/transactional-templates.d.ts +5 -0
- package/dist/commands/transactional-templates.d.ts.map +1 -0
- package/dist/commands/transactional-templates.js +354 -0
- package/dist/commands/transactional-templates.js.map +1 -0
- package/dist/commands/webhooks.js +1 -1
- package/dist/commands/webhooks.js.map +1 -1
- package/dist/utils/auth.d.ts +8 -1
- package/dist/utils/auth.d.ts.map +1 -1
- package/dist/utils/auth.js +39 -11
- package/dist/utils/auth.js.map +1 -1
- package/dist/utils/config-file.d.ts +7 -0
- package/dist/utils/config-file.d.ts.map +1 -1
- package/dist/utils/config-file.js +15 -0
- package/dist/utils/config-file.js.map +1 -1
- package/dist/utils/config.d.ts +2 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +12 -4
- 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/list-defaults.d.ts +33 -0
- package/dist/utils/list-defaults.d.ts.map +1 -0
- package/dist/utils/list-defaults.js +52 -0
- package/dist/utils/list-defaults.js.map +1 -0
- package/dist/utils/output.d.ts.map +1 -1
- package/dist/utils/output.js +36 -13
- package/dist/utils/output.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 -47
- 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,997 @@
|
|
|
1
|
+
# Campaign Testing
|
|
2
|
+
|
|
3
|
+
Test campaigns thoroughly before sending to ensure perfect delivery and presentation.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Campaign testing allows you to:
|
|
8
|
+
- Send test emails to verify appearance
|
|
9
|
+
- Check content, links, and formatting
|
|
10
|
+
- Test merge tags and personalization
|
|
11
|
+
- Preview in multiple email clients
|
|
12
|
+
- Validate before scheduling
|
|
13
|
+
- Catch errors early
|
|
14
|
+
|
|
15
|
+
Testing is critical to ensure campaigns look professional and function correctly across different email clients and devices.
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
### Send a Test Email
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
$ cakemail campaigns test 790 -e test@example.com
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Output:**
|
|
26
|
+
```
|
|
27
|
+
✓ Test email sent to test@example.com
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Check your inbox to review the campaign.
|
|
31
|
+
|
|
32
|
+
## Test Email Basics
|
|
33
|
+
|
|
34
|
+
### Send to Single Recipient
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
$ cakemail campaigns test 790 -e john@company.com
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Output:**
|
|
41
|
+
```
|
|
42
|
+
✓ Test email sent to john@company.com
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Send to Multiple Recipients
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
$ cakemail campaigns test 790 -e john@company.com,mary@company.com,team@company.com
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Output:**
|
|
52
|
+
```
|
|
53
|
+
✓ Test email sent to 3 recipients:
|
|
54
|
+
• john@company.com
|
|
55
|
+
• mary@company.com
|
|
56
|
+
• team@company.com
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Send to Team Distribution List
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Set up team emails in environment
|
|
63
|
+
$ export TEST_TEAM="editor@company.com,designer@company.com,manager@company.com"
|
|
64
|
+
|
|
65
|
+
$ cakemail campaigns test 790 -e $TEST_TEAM
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Testing Workflow
|
|
69
|
+
|
|
70
|
+
### Pre-Send Testing Checklist
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
#!/bin/bash
|
|
74
|
+
# pre-send-test.sh
|
|
75
|
+
|
|
76
|
+
CAMPAIGN_ID=$1
|
|
77
|
+
|
|
78
|
+
if [ -z "$CAMPAIGN_ID" ]; then
|
|
79
|
+
echo "Usage: $0 <campaign-id>"
|
|
80
|
+
exit 1
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
echo "=== Pre-Send Testing for Campaign $CAMPAIGN_ID ==="
|
|
84
|
+
echo ""
|
|
85
|
+
|
|
86
|
+
# Step 1: Get campaign details
|
|
87
|
+
echo "1. Reviewing campaign details..."
|
|
88
|
+
CAMPAIGN=$(cakemail campaigns get $CAMPAIGN_ID -f json)
|
|
89
|
+
SUBJECT=$(echo "$CAMPAIGN" | jq -r '.subject')
|
|
90
|
+
SENDER=$(echo "$CAMPAIGN" | jq -r '.sender_name')
|
|
91
|
+
FROM=$(echo "$CAMPAIGN" | jq -r '.sender_email')
|
|
92
|
+
|
|
93
|
+
echo " Subject: $SUBJECT"
|
|
94
|
+
echo " From: $SENDER <$FROM>"
|
|
95
|
+
echo ""
|
|
96
|
+
|
|
97
|
+
# Step 2: Send test to review team
|
|
98
|
+
echo "2. Sending test email to review team..."
|
|
99
|
+
cakemail campaigns test $CAMPAIGN_ID -e "editor@company.com,designer@company.com"
|
|
100
|
+
echo ""
|
|
101
|
+
|
|
102
|
+
# Step 3: Wait for review
|
|
103
|
+
echo "3. Review test email for:"
|
|
104
|
+
echo " ☐ Subject line clear and compelling"
|
|
105
|
+
echo " ☐ Sender name correct"
|
|
106
|
+
echo " ☐ Header/footer present"
|
|
107
|
+
echo " ☐ All images load"
|
|
108
|
+
echo " ☐ All links work"
|
|
109
|
+
echo " ☐ Merge tags display correctly"
|
|
110
|
+
echo " ☐ Mobile responsive"
|
|
111
|
+
echo " ☐ Unsubscribe link present"
|
|
112
|
+
echo ""
|
|
113
|
+
|
|
114
|
+
# Step 4: Get approval
|
|
115
|
+
read -p "Tests passed? (yes/no): " APPROVAL
|
|
116
|
+
|
|
117
|
+
if [ "$APPROVAL" == "yes" ]; then
|
|
118
|
+
echo ""
|
|
119
|
+
echo "✅ Campaign ready for scheduling"
|
|
120
|
+
echo " Run: cakemail campaigns schedule $CAMPAIGN_ID"
|
|
121
|
+
else
|
|
122
|
+
echo ""
|
|
123
|
+
echo "⚠️ Review feedback and make changes"
|
|
124
|
+
echo " Run: cakemail campaigns update $CAMPAIGN_ID --subject \"New Subject\""
|
|
125
|
+
fi
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Make this executable:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
$ chmod +x pre-send-test.sh
|
|
132
|
+
$ ./pre-send-test.sh 790
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Testing Merge Tags
|
|
136
|
+
|
|
137
|
+
### Test Personalization
|
|
138
|
+
|
|
139
|
+
Campaign with merge tags:
|
|
140
|
+
|
|
141
|
+
```html
|
|
142
|
+
<p>Hi {{first_name}},</p>
|
|
143
|
+
<p>Your account status: {{custom_attributes.plan_type}}</p>
|
|
144
|
+
<p>Signed up: {{custom_attributes.signup_date}}</p>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Test with sample data:**
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# Create test contact with sample data
|
|
151
|
+
$ cakemail contacts add \
|
|
152
|
+
-e "testuser@example.com" \
|
|
153
|
+
--first-name "John" \
|
|
154
|
+
--last-name "Doe" \
|
|
155
|
+
-d '{"plan_type":"premium","signup_date":"2024-01-15"}'
|
|
156
|
+
|
|
157
|
+
# Send test
|
|
158
|
+
$ cakemail campaigns test 790 -e testuser@example.com
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Test email will show:**
|
|
162
|
+
```
|
|
163
|
+
Hi John,
|
|
164
|
+
Your account status: premium
|
|
165
|
+
Signed up: 2024-01-15
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Test with Missing Data
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# Create contact without custom attributes
|
|
172
|
+
$ cakemail contacts add -e "incomplete@example.com" --first-name "Jane"
|
|
173
|
+
|
|
174
|
+
# Send test
|
|
175
|
+
$ cakemail campaigns test 790 -e incomplete@example.com
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Verify fallbacks:**
|
|
179
|
+
- Missing first_name → Check fallback text
|
|
180
|
+
- Missing custom_attributes → Ensure no broken tags
|
|
181
|
+
|
|
182
|
+
### Test Multiple Scenarios
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
#!/bin/bash
|
|
186
|
+
# test-personalization.sh
|
|
187
|
+
|
|
188
|
+
CAMPAIGN_ID=790
|
|
189
|
+
|
|
190
|
+
# Test Scenario 1: Complete data
|
|
191
|
+
echo "Testing with complete data..."
|
|
192
|
+
cakemail campaigns test $CAMPAIGN_ID -e john.complete@test.com
|
|
193
|
+
|
|
194
|
+
# Test Scenario 2: Missing first name
|
|
195
|
+
echo "Testing with missing first name..."
|
|
196
|
+
cakemail campaigns test $CAMPAIGN_ID -e nofirstname@test.com
|
|
197
|
+
|
|
198
|
+
# Test Scenario 3: Missing custom attributes
|
|
199
|
+
echo "Testing with missing attributes..."
|
|
200
|
+
cakemail campaigns test $CAMPAIGN_ID -e noattrs@test.com
|
|
201
|
+
|
|
202
|
+
echo ""
|
|
203
|
+
echo "✅ All test scenarios sent"
|
|
204
|
+
echo "Review each test email to verify merge tag behavior"
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Testing Links
|
|
208
|
+
|
|
209
|
+
### Verify All Links Work
|
|
210
|
+
|
|
211
|
+
After sending test:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
#!/bin/bash
|
|
215
|
+
# check-links.sh
|
|
216
|
+
|
|
217
|
+
TEST_EMAIL="test@example.com"
|
|
218
|
+
|
|
219
|
+
echo "=== Link Testing Checklist ==="
|
|
220
|
+
echo ""
|
|
221
|
+
echo "Test email sent to: $TEST_EMAIL"
|
|
222
|
+
echo ""
|
|
223
|
+
echo "Manual checks required:"
|
|
224
|
+
echo ""
|
|
225
|
+
echo "☐ Header logo links to website"
|
|
226
|
+
echo "☐ CTA button links correctly"
|
|
227
|
+
echo "☐ Product links include tracking parameters"
|
|
228
|
+
echo "☐ Social media icons link to profiles"
|
|
229
|
+
echo "☐ Unsubscribe link works"
|
|
230
|
+
echo "☐ View in browser link works"
|
|
231
|
+
echo "☐ Footer address/contact links work"
|
|
232
|
+
echo ""
|
|
233
|
+
echo "Verify tracking:"
|
|
234
|
+
echo "☐ Links include click tracking"
|
|
235
|
+
echo "☐ UTM parameters present"
|
|
236
|
+
echo "☐ Custom tracking parameters correct"
|
|
237
|
+
echo ""
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Test Link Tracking
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
# Get campaign with tracking enabled
|
|
244
|
+
$ cakemail campaigns get 790 -f json | jq '{id, name, tracking_enabled: .settings.track_clicks}'
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Output:**
|
|
248
|
+
```json
|
|
249
|
+
{
|
|
250
|
+
"id": 790,
|
|
251
|
+
"name": "March Newsletter",
|
|
252
|
+
"tracking_enabled": true
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**In test email:**
|
|
257
|
+
- Links should be wrapped with tracking domain
|
|
258
|
+
- Example: `https://tracking.cakemail.com/click/abc123...`
|
|
259
|
+
- Clicking link redirects to actual destination
|
|
260
|
+
|
|
261
|
+
## Cross-Client Testing
|
|
262
|
+
|
|
263
|
+
### Test in Multiple Email Clients
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
#!/bin/bash
|
|
267
|
+
# multi-client-test.sh
|
|
268
|
+
|
|
269
|
+
CAMPAIGN_ID=790
|
|
270
|
+
|
|
271
|
+
echo "=== Multi-Client Testing ==="
|
|
272
|
+
echo ""
|
|
273
|
+
echo "Sending test emails to various clients..."
|
|
274
|
+
echo ""
|
|
275
|
+
|
|
276
|
+
# Gmail
|
|
277
|
+
cakemail campaigns test $CAMPAIGN_ID -e your.gmail@gmail.com
|
|
278
|
+
echo "✓ Gmail test sent"
|
|
279
|
+
|
|
280
|
+
# Outlook
|
|
281
|
+
cakemail campaigns test $CAMPAIGN_ID -e your.outlook@outlook.com
|
|
282
|
+
echo "✓ Outlook test sent"
|
|
283
|
+
|
|
284
|
+
# Apple Mail
|
|
285
|
+
cakemail campaigns test $CAMPAIGN_ID -e your.apple@icloud.com
|
|
286
|
+
echo "✓ Apple Mail test sent"
|
|
287
|
+
|
|
288
|
+
# Yahoo
|
|
289
|
+
cakemail campaigns test $CAMPAIGN_ID -e your.yahoo@yahoo.com
|
|
290
|
+
echo "✓ Yahoo test sent"
|
|
291
|
+
|
|
292
|
+
echo ""
|
|
293
|
+
echo "Check each client for:"
|
|
294
|
+
echo " • Layout/formatting"
|
|
295
|
+
echo " • Image display"
|
|
296
|
+
echo " • Font rendering"
|
|
297
|
+
echo " • Button styling"
|
|
298
|
+
echo " • Responsive behavior"
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Device Testing
|
|
302
|
+
|
|
303
|
+
Test on different devices:
|
|
304
|
+
|
|
305
|
+
1. **Desktop** - Send to desktop email client
|
|
306
|
+
2. **Mobile** - Check on phone
|
|
307
|
+
3. **Tablet** - Verify tablet layout
|
|
308
|
+
4. **Webmail** - Test in browser
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
# Send test for mobile review
|
|
312
|
+
$ cakemail campaigns test 790 -e your.phone@gmail.com
|
|
313
|
+
|
|
314
|
+
# Check on mobile device:
|
|
315
|
+
# - Text readable without zooming
|
|
316
|
+
# - Buttons large enough to tap
|
|
317
|
+
# - Images scale properly
|
|
318
|
+
# - Single-column layout
|
|
319
|
+
# - CTA buttons prominent
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Testing Templates
|
|
323
|
+
|
|
324
|
+
### Test Template with Content
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
# Create campaign from template
|
|
328
|
+
$ CAMPAIGN_ID=$(cakemail campaigns create \
|
|
329
|
+
-n "Template Test" \
|
|
330
|
+
-l 123 \
|
|
331
|
+
-s 101 \
|
|
332
|
+
--template 201 \
|
|
333
|
+
-f json | jq -r '.id')
|
|
334
|
+
|
|
335
|
+
# Send test
|
|
336
|
+
$ cakemail campaigns test $CAMPAIGN_ID -e test@example.com
|
|
337
|
+
|
|
338
|
+
# Review:
|
|
339
|
+
# - Template structure correct
|
|
340
|
+
# - Content areas filled properly
|
|
341
|
+
# - Template merge tags work
|
|
342
|
+
# - Styling consistent
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Test Template Changes
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
#!/bin/bash
|
|
349
|
+
# test-template-changes.sh
|
|
350
|
+
|
|
351
|
+
TEMPLATE_ID=201
|
|
352
|
+
|
|
353
|
+
echo "Testing template changes..."
|
|
354
|
+
|
|
355
|
+
# Create test campaign
|
|
356
|
+
CAMPAIGN=$(cakemail campaigns create \
|
|
357
|
+
-n "Template Test $(date +%s)" \
|
|
358
|
+
-l 123 \
|
|
359
|
+
-s 101 \
|
|
360
|
+
--template $TEMPLATE_ID \
|
|
361
|
+
-f json)
|
|
362
|
+
|
|
363
|
+
CAMPAIGN_ID=$(echo "$CAMPAIGN" | jq -r '.id')
|
|
364
|
+
|
|
365
|
+
echo "Created test campaign: $CAMPAIGN_ID"
|
|
366
|
+
|
|
367
|
+
# Send test
|
|
368
|
+
cakemail campaigns test $CAMPAIGN_ID -e template-review@company.com
|
|
369
|
+
|
|
370
|
+
echo ""
|
|
371
|
+
echo "✓ Test sent to template-review@company.com"
|
|
372
|
+
echo ""
|
|
373
|
+
echo "Verify:"
|
|
374
|
+
echo " • Template changes applied correctly"
|
|
375
|
+
echo " • No broken layouts"
|
|
376
|
+
echo " • All sections render properly"
|
|
377
|
+
echo ""
|
|
378
|
+
|
|
379
|
+
# Clean up
|
|
380
|
+
read -p "Delete test campaign? (yes/no): " DELETE
|
|
381
|
+
if [ "$DELETE" == "yes" ]; then
|
|
382
|
+
cakemail campaigns delete $CAMPAIGN_ID --force
|
|
383
|
+
echo "✓ Test campaign deleted"
|
|
384
|
+
fi
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
## A/B Testing
|
|
388
|
+
|
|
389
|
+
### Test Subject Lines
|
|
390
|
+
|
|
391
|
+
Create variations to test:
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
#!/bin/bash
|
|
395
|
+
# ab-test-subjects.sh
|
|
396
|
+
|
|
397
|
+
LIST_ID=123
|
|
398
|
+
SENDER_ID=101
|
|
399
|
+
TEMPLATE=201
|
|
400
|
+
|
|
401
|
+
# Version A
|
|
402
|
+
ID_A=$(cakemail campaigns create \
|
|
403
|
+
-n "A/B Test - Subject A" \
|
|
404
|
+
-l $LIST_ID \
|
|
405
|
+
-s $SENDER_ID \
|
|
406
|
+
--template $TEMPLATE \
|
|
407
|
+
--subject "Save 20% This Week" \
|
|
408
|
+
-f json | jq -r '.id')
|
|
409
|
+
|
|
410
|
+
# Version B
|
|
411
|
+
ID_B=$(cakemail campaigns create \
|
|
412
|
+
-n "A/B Test - Subject B" \
|
|
413
|
+
-l $LIST_ID \
|
|
414
|
+
-s $SENDER_ID \
|
|
415
|
+
--template $TEMPLATE \
|
|
416
|
+
--subject "Your Exclusive 20% Discount" \
|
|
417
|
+
-f json | jq -r '.id')
|
|
418
|
+
|
|
419
|
+
echo "Created A/B test campaigns:"
|
|
420
|
+
echo "Version A (ID: $ID_A): Save 20% This Week"
|
|
421
|
+
echo "Version B (ID: $ID_B): Your Exclusive 20% Discount"
|
|
422
|
+
echo ""
|
|
423
|
+
|
|
424
|
+
# Send tests
|
|
425
|
+
echo "Sending tests for review..."
|
|
426
|
+
cakemail campaigns test $ID_A -e team@company.com
|
|
427
|
+
cakemail campaigns test $ID_B -e team@company.com
|
|
428
|
+
|
|
429
|
+
echo ""
|
|
430
|
+
echo "✓ Both versions sent to team@company.com"
|
|
431
|
+
echo ""
|
|
432
|
+
echo "Compare and decide which to use"
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Test Content Variations
|
|
436
|
+
|
|
437
|
+
```bash
|
|
438
|
+
#!/bin/bash
|
|
439
|
+
# ab-test-content.sh
|
|
440
|
+
|
|
441
|
+
# Version A: Short form
|
|
442
|
+
ID_A=$(cakemail campaigns create \
|
|
443
|
+
-n "A/B Test - Short Content" \
|
|
444
|
+
-l 123 \
|
|
445
|
+
-s 101 \
|
|
446
|
+
--html "<h1>Quick Update</h1><p>Brief message...</p>" \
|
|
447
|
+
--subject "Quick Update" \
|
|
448
|
+
-f json | jq -r '.id')
|
|
449
|
+
|
|
450
|
+
# Version B: Long form
|
|
451
|
+
ID_B=$(cakemail campaigns create \
|
|
452
|
+
-n "A/B Test - Long Content" \
|
|
453
|
+
-l 123 \
|
|
454
|
+
-s 101 \
|
|
455
|
+
--html "<h1>Detailed Update</h1><p>Long detailed message...</p>" \
|
|
456
|
+
--subject "Detailed Update" \
|
|
457
|
+
-f json | jq -r '.id')
|
|
458
|
+
|
|
459
|
+
# Send tests
|
|
460
|
+
cakemail campaigns test $ID_A -e review@company.com
|
|
461
|
+
cakemail campaigns test $ID_B -e review@company.com
|
|
462
|
+
|
|
463
|
+
echo "A/B content test sent"
|
|
464
|
+
echo "Choose version with better engagement"
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
## Testing Best Practices
|
|
468
|
+
|
|
469
|
+
### 1. Always Test Before Scheduling
|
|
470
|
+
|
|
471
|
+
```bash
|
|
472
|
+
# Bad: Schedule without testing
|
|
473
|
+
$ cakemail campaigns schedule 790 # ❌
|
|
474
|
+
|
|
475
|
+
# Good: Test first, then schedule
|
|
476
|
+
$ cakemail campaigns test 790 -e team@company.com # ✅
|
|
477
|
+
# Review email
|
|
478
|
+
$ cakemail campaigns schedule 790
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### 2. Test with Real Data
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
# Create realistic test contact
|
|
485
|
+
$ cakemail contacts add \
|
|
486
|
+
-e "realistic.test@example.com" \
|
|
487
|
+
--first-name "John" \
|
|
488
|
+
--last-name "Smith" \
|
|
489
|
+
-d '{
|
|
490
|
+
"plan_type": "premium",
|
|
491
|
+
"signup_date": "2024-01-15",
|
|
492
|
+
"purchase_count": 5,
|
|
493
|
+
"is_vip": true
|
|
494
|
+
}'
|
|
495
|
+
|
|
496
|
+
# Test shows how real subscribers will see it
|
|
497
|
+
$ cakemail campaigns test 790 -e realistic.test@example.com
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### 3. Test Multiple Times
|
|
501
|
+
|
|
502
|
+
```bash
|
|
503
|
+
#!/bin/bash
|
|
504
|
+
# iterative-testing.sh
|
|
505
|
+
|
|
506
|
+
CAMPAIGN_ID=790
|
|
507
|
+
|
|
508
|
+
# Round 1: Initial test
|
|
509
|
+
echo "Round 1: Initial review..."
|
|
510
|
+
cakemail campaigns test $CAMPAIGN_ID -e editor@company.com
|
|
511
|
+
read -p "Issues found? (yes/no): " HAS_ISSUES
|
|
512
|
+
|
|
513
|
+
while [ "$HAS_ISSUES" == "yes" ]; do
|
|
514
|
+
echo "Make changes to campaign..."
|
|
515
|
+
read -p "Press Enter when changes made..."
|
|
516
|
+
|
|
517
|
+
# Send new test
|
|
518
|
+
cakemail campaigns test $CAMPAIGN_ID -e editor@company.com
|
|
519
|
+
read -p "Issues found? (yes/no): " HAS_ISSUES
|
|
520
|
+
done
|
|
521
|
+
|
|
522
|
+
echo "✅ Campaign approved"
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
### 4. Document Test Results
|
|
526
|
+
|
|
527
|
+
```bash
|
|
528
|
+
#!/bin/bash
|
|
529
|
+
# log-test-results.sh
|
|
530
|
+
|
|
531
|
+
CAMPAIGN_ID=$1
|
|
532
|
+
LOG_FILE="campaign-tests.log"
|
|
533
|
+
|
|
534
|
+
echo "=== Test Log ===" >> $LOG_FILE
|
|
535
|
+
echo "Date: $(date)" >> $LOG_FILE
|
|
536
|
+
echo "Campaign: $CAMPAIGN_ID" >> $LOG_FILE
|
|
537
|
+
echo "Tester: $USER" >> $LOG_FILE
|
|
538
|
+
echo "" >> $LOG_FILE
|
|
539
|
+
|
|
540
|
+
read -p "Test passed? (yes/no): " RESULT
|
|
541
|
+
echo "Result: $RESULT" >> $LOG_FILE
|
|
542
|
+
|
|
543
|
+
if [ "$RESULT" != "yes" ]; then
|
|
544
|
+
read -p "Issues found: " ISSUES
|
|
545
|
+
echo "Issues: $ISSUES" >> $LOG_FILE
|
|
546
|
+
fi
|
|
547
|
+
|
|
548
|
+
echo "---" >> $LOG_FILE
|
|
549
|
+
echo "" >> $LOG_FILE
|
|
550
|
+
|
|
551
|
+
cat $LOG_FILE
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### 5. Use Test Distribution Lists
|
|
555
|
+
|
|
556
|
+
Create reusable test groups:
|
|
557
|
+
|
|
558
|
+
```bash
|
|
559
|
+
# Set in environment or script
|
|
560
|
+
export TEST_EDITORS="editor1@company.com,editor2@company.com"
|
|
561
|
+
export TEST_DESIGNERS="designer1@company.com,designer2@company.com"
|
|
562
|
+
export TEST_ALL="editor1@company.com,editor2@company.com,designer1@company.com,designer2@company.com,manager@company.com"
|
|
563
|
+
|
|
564
|
+
# Use in tests
|
|
565
|
+
$ cakemail campaigns test 790 -e $TEST_EDITORS # Content review
|
|
566
|
+
$ cakemail campaigns test 790 -e $TEST_DESIGNERS # Visual review
|
|
567
|
+
$ cakemail campaigns test 790 -e $TEST_ALL # Final review
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
## Advanced Testing Workflows
|
|
571
|
+
|
|
572
|
+
### Workflow 1: Comprehensive Testing
|
|
573
|
+
|
|
574
|
+
```bash
|
|
575
|
+
#!/bin/bash
|
|
576
|
+
# comprehensive-test.sh
|
|
577
|
+
|
|
578
|
+
CAMPAIGN_ID=$1
|
|
579
|
+
|
|
580
|
+
echo "=== Comprehensive Campaign Testing ==="
|
|
581
|
+
echo ""
|
|
582
|
+
|
|
583
|
+
# 1. Campaign details
|
|
584
|
+
echo "1. Campaign Details:"
|
|
585
|
+
CAMPAIGN=$(cakemail campaigns get $CAMPAIGN_ID -f json)
|
|
586
|
+
echo " Name: $(echo "$CAMPAIGN" | jq -r '.name')"
|
|
587
|
+
echo " Subject: $(echo "$CAMPAIGN" | jq -r '.subject')"
|
|
588
|
+
echo " List: $(echo "$CAMPAIGN" | jq -r '.list_id')"
|
|
589
|
+
echo ""
|
|
590
|
+
|
|
591
|
+
# 2. Content test
|
|
592
|
+
echo "2. Sending content review test..."
|
|
593
|
+
cakemail campaigns test $CAMPAIGN_ID -e editor@company.com
|
|
594
|
+
echo " ✓ Sent to editor@company.com"
|
|
595
|
+
echo ""
|
|
596
|
+
|
|
597
|
+
# 3. Design test
|
|
598
|
+
echo "3. Sending design review test..."
|
|
599
|
+
cakemail campaigns test $CAMPAIGN_ID -e designer@company.com
|
|
600
|
+
echo " ✓ Sent to designer@company.com"
|
|
601
|
+
echo ""
|
|
602
|
+
|
|
603
|
+
# 4. Multi-client test
|
|
604
|
+
echo "4. Sending multi-client tests..."
|
|
605
|
+
cakemail campaigns test $CAMPAIGN_ID -e gmail.test@gmail.com
|
|
606
|
+
cakemail campaigns test $CAMPAIGN_ID -e outlook.test@outlook.com
|
|
607
|
+
echo " ✓ Sent to multiple clients"
|
|
608
|
+
echo ""
|
|
609
|
+
|
|
610
|
+
# 5. Mobile test
|
|
611
|
+
echo "5. Sending mobile test..."
|
|
612
|
+
cakemail campaigns test $CAMPAIGN_ID -e mobile.test@gmail.com
|
|
613
|
+
echo " ✓ Sent for mobile review"
|
|
614
|
+
echo ""
|
|
615
|
+
|
|
616
|
+
# 6. Link verification
|
|
617
|
+
echo "6. Link Verification:"
|
|
618
|
+
echo " Manual check required:"
|
|
619
|
+
echo " • Click all links in test email"
|
|
620
|
+
echo " • Verify tracking parameters"
|
|
621
|
+
echo " • Test unsubscribe flow"
|
|
622
|
+
echo ""
|
|
623
|
+
|
|
624
|
+
# 7. Approval
|
|
625
|
+
read -p "All tests passed? (yes/no): " APPROVED
|
|
626
|
+
|
|
627
|
+
if [ "$APPROVED" == "yes" ]; then
|
|
628
|
+
echo ""
|
|
629
|
+
echo "✅ Campaign ready for scheduling"
|
|
630
|
+
read -p "Schedule now? (yes/no): " SCHEDULE
|
|
631
|
+
|
|
632
|
+
if [ "$SCHEDULE" == "yes" ]; then
|
|
633
|
+
cakemail campaigns schedule $CAMPAIGN_ID
|
|
634
|
+
fi
|
|
635
|
+
else
|
|
636
|
+
echo ""
|
|
637
|
+
echo "⚠️ Address issues before scheduling"
|
|
638
|
+
fi
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
### Workflow 2: Regression Testing
|
|
642
|
+
|
|
643
|
+
Test existing campaigns after template changes:
|
|
644
|
+
|
|
645
|
+
```bash
|
|
646
|
+
#!/bin/bash
|
|
647
|
+
# regression-test.sh
|
|
648
|
+
|
|
649
|
+
TEMPLATE_ID=201
|
|
650
|
+
|
|
651
|
+
echo "=== Template Regression Testing ==="
|
|
652
|
+
echo ""
|
|
653
|
+
|
|
654
|
+
# Find all campaigns using this template
|
|
655
|
+
CAMPAIGNS=$(cakemail campaigns list \
|
|
656
|
+
--filter "template_id==$TEMPLATE_ID;status==draft" \
|
|
657
|
+
-f json | jq -r '.data[].id')
|
|
658
|
+
|
|
659
|
+
if [ -z "$CAMPAIGNS" ]; then
|
|
660
|
+
echo "No draft campaigns using template $TEMPLATE_ID"
|
|
661
|
+
exit 0
|
|
662
|
+
fi
|
|
663
|
+
|
|
664
|
+
echo "Found campaigns using template $TEMPLATE_ID:"
|
|
665
|
+
for ID in $CAMPAIGNS; do
|
|
666
|
+
NAME=$(cakemail campaigns get $ID -f json | jq -r '.name')
|
|
667
|
+
echo " • $NAME (ID: $ID)"
|
|
668
|
+
done
|
|
669
|
+
|
|
670
|
+
echo ""
|
|
671
|
+
echo "Sending regression tests..."
|
|
672
|
+
|
|
673
|
+
for ID in $CAMPAIGNS; do
|
|
674
|
+
cakemail campaigns test $ID -e regression@company.com
|
|
675
|
+
echo " ✓ Test sent for campaign $ID"
|
|
676
|
+
done
|
|
677
|
+
|
|
678
|
+
echo ""
|
|
679
|
+
echo "✅ All regression tests sent to regression@company.com"
|
|
680
|
+
echo "Verify template changes don't break existing campaigns"
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
### Workflow 3: Stakeholder Review
|
|
684
|
+
|
|
685
|
+
```bash
|
|
686
|
+
#!/bin/bash
|
|
687
|
+
# stakeholder-review.sh
|
|
688
|
+
|
|
689
|
+
CAMPAIGN_ID=$1
|
|
690
|
+
|
|
691
|
+
echo "=== Stakeholder Review Process ==="
|
|
692
|
+
echo ""
|
|
693
|
+
|
|
694
|
+
# Define stakeholders
|
|
695
|
+
STAKEHOLDERS=(
|
|
696
|
+
"editor@company.com:Content Editor"
|
|
697
|
+
"designer@company.com:Designer"
|
|
698
|
+
"manager@company.com:Marketing Manager"
|
|
699
|
+
"legal@company.com:Legal Compliance"
|
|
700
|
+
)
|
|
701
|
+
|
|
702
|
+
# Send to each stakeholder
|
|
703
|
+
for STAKEHOLDER in "${STAKEHOLDERS[@]}"; do
|
|
704
|
+
EMAIL=$(echo $STAKEHOLDER | cut -d: -f1)
|
|
705
|
+
ROLE=$(echo $STAKEHOLDER | cut -d: -f2)
|
|
706
|
+
|
|
707
|
+
echo "Sending to $ROLE ($EMAIL)..."
|
|
708
|
+
cakemail campaigns test $CAMPAIGN_ID -e $EMAIL
|
|
709
|
+
echo " ✓ Sent"
|
|
710
|
+
done
|
|
711
|
+
|
|
712
|
+
echo ""
|
|
713
|
+
echo "✅ Review requests sent to all stakeholders"
|
|
714
|
+
echo ""
|
|
715
|
+
echo "Stakeholder Approval Checklist:"
|
|
716
|
+
for STAKEHOLDER in "${STAKEHOLDERS[@]}"; do
|
|
717
|
+
ROLE=$(echo $STAKEHOLDER | cut -d: -f2)
|
|
718
|
+
echo " ☐ $ROLE approval"
|
|
719
|
+
done
|
|
720
|
+
|
|
721
|
+
echo ""
|
|
722
|
+
read -p "All approvals received? (yes/no): " ALL_APPROVED
|
|
723
|
+
|
|
724
|
+
if [ "$ALL_APPROVED" == "yes" ]; then
|
|
725
|
+
echo "✅ Campaign approved for scheduling"
|
|
726
|
+
else
|
|
727
|
+
echo "⚠️ Waiting for approvals..."
|
|
728
|
+
fi
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
### Workflow 4: Automated Quality Checks
|
|
732
|
+
|
|
733
|
+
```bash
|
|
734
|
+
#!/bin/bash
|
|
735
|
+
# quality-checks.sh
|
|
736
|
+
|
|
737
|
+
CAMPAIGN_ID=$1
|
|
738
|
+
|
|
739
|
+
echo "=== Automated Quality Checks ==="
|
|
740
|
+
echo ""
|
|
741
|
+
|
|
742
|
+
CAMPAIGN=$(cakemail campaigns get $CAMPAIGN_ID -f json)
|
|
743
|
+
|
|
744
|
+
# Check 1: Subject line
|
|
745
|
+
SUBJECT=$(echo "$CAMPAIGN" | jq -r '.subject')
|
|
746
|
+
SUBJECT_LEN=${#SUBJECT}
|
|
747
|
+
|
|
748
|
+
echo "Check 1: Subject Line"
|
|
749
|
+
if [ $SUBJECT_LEN -gt 60 ]; then
|
|
750
|
+
echo " ⚠️ Subject too long ($SUBJECT_LEN chars, recommended < 60)"
|
|
751
|
+
else
|
|
752
|
+
echo " ✅ Subject length OK ($SUBJECT_LEN chars)"
|
|
753
|
+
fi
|
|
754
|
+
|
|
755
|
+
# Check 2: Has HTML content
|
|
756
|
+
HAS_HTML=$(echo "$CAMPAIGN" | jq -r '.html' | grep -v "null")
|
|
757
|
+
echo "Check 2: HTML Content"
|
|
758
|
+
if [ -z "$HAS_HTML" ]; then
|
|
759
|
+
echo " ❌ No HTML content"
|
|
760
|
+
else
|
|
761
|
+
echo " ✅ HTML content present"
|
|
762
|
+
fi
|
|
763
|
+
|
|
764
|
+
# Check 3: Has plain text
|
|
765
|
+
HAS_TEXT=$(echo "$CAMPAIGN" | jq -r '.text' | grep -v "null")
|
|
766
|
+
echo "Check 3: Plain Text Version"
|
|
767
|
+
if [ -z "$HAS_TEXT" ]; then
|
|
768
|
+
echo " ⚠️ No plain text version (recommended)"
|
|
769
|
+
else
|
|
770
|
+
echo " ✅ Plain text present"
|
|
771
|
+
fi
|
|
772
|
+
|
|
773
|
+
# Check 4: Sender verified
|
|
774
|
+
SENDER_ID=$(echo "$CAMPAIGN" | jq -r '.sender_id')
|
|
775
|
+
SENDER_CONFIRMED=$(cakemail senders get $SENDER_ID -f json | jq -r '.confirmed')
|
|
776
|
+
echo "Check 4: Sender Verification"
|
|
777
|
+
if [ "$SENDER_CONFIRMED" != "true" ]; then
|
|
778
|
+
echo " ❌ Sender not verified"
|
|
779
|
+
else
|
|
780
|
+
echo " ✅ Sender verified"
|
|
781
|
+
fi
|
|
782
|
+
|
|
783
|
+
# Check 5: List has contacts
|
|
784
|
+
LIST_ID=$(echo "$CAMPAIGN" | jq -r '.list_id')
|
|
785
|
+
CONTACT_COUNT=$(cakemail contacts list $LIST_ID -f json | jq '.count')
|
|
786
|
+
echo "Check 5: Recipient List"
|
|
787
|
+
if [ "$CONTACT_COUNT" -eq 0 ]; then
|
|
788
|
+
echo " ⚠️ List has 0 contacts"
|
|
789
|
+
else
|
|
790
|
+
echo " ✅ List has $CONTACT_COUNT contacts"
|
|
791
|
+
fi
|
|
792
|
+
|
|
793
|
+
echo ""
|
|
794
|
+
|
|
795
|
+
# Send test if checks pass
|
|
796
|
+
if [ "$SENDER_CONFIRMED" == "true" ] && [ -n "$HAS_HTML" ]; then
|
|
797
|
+
echo "Quality checks passed. Sending test..."
|
|
798
|
+
cakemail campaigns test $CAMPAIGN_ID -e quality@company.com
|
|
799
|
+
echo "✅ Test sent to quality@company.com"
|
|
800
|
+
else
|
|
801
|
+
echo "❌ Quality checks failed. Fix issues before testing."
|
|
802
|
+
fi
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
## Testing Checklist
|
|
806
|
+
|
|
807
|
+
### Before Sending Test
|
|
808
|
+
|
|
809
|
+
```
|
|
810
|
+
☐ Campaign created and saved
|
|
811
|
+
☐ HTML content added
|
|
812
|
+
☐ Plain text version added (optional but recommended)
|
|
813
|
+
☐ Subject line written
|
|
814
|
+
☐ Sender verified
|
|
815
|
+
☐ List selected
|
|
816
|
+
☐ Merge tags tested
|
|
817
|
+
☐ Links include tracking parameters
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
### After Receiving Test
|
|
821
|
+
|
|
822
|
+
```
|
|
823
|
+
☐ Subject line displays correctly
|
|
824
|
+
☐ Sender name and email correct
|
|
825
|
+
☐ Header loads properly
|
|
826
|
+
☐ Body content formatted correctly
|
|
827
|
+
☐ Images all load
|
|
828
|
+
☐ Buttons display and are clickable
|
|
829
|
+
☐ All links work
|
|
830
|
+
☐ Merge tags filled correctly
|
|
831
|
+
☐ Footer present with required info
|
|
832
|
+
☐ Unsubscribe link works
|
|
833
|
+
☐ Mobile responsive
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
### Cross-Client Checks
|
|
837
|
+
|
|
838
|
+
```
|
|
839
|
+
☐ Gmail (web and app)
|
|
840
|
+
☐ Outlook (desktop and web)
|
|
841
|
+
☐ Apple Mail
|
|
842
|
+
☐ iPhone Mail app
|
|
843
|
+
☐ Android Gmail app
|
|
844
|
+
☐ Dark mode (if supported)
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
## Troubleshooting
|
|
848
|
+
|
|
849
|
+
### Test Email Not Received
|
|
850
|
+
|
|
851
|
+
**Problem:** Test email not arriving
|
|
852
|
+
|
|
853
|
+
**Solutions:**
|
|
854
|
+
|
|
855
|
+
```bash
|
|
856
|
+
# Check campaign status
|
|
857
|
+
$ cakemail campaigns get 790 -f json | jq '{status, subject}'
|
|
858
|
+
|
|
859
|
+
# Verify sender is confirmed
|
|
860
|
+
$ cakemail senders list -f json | jq '.data[] | select(.confirmed == true)'
|
|
861
|
+
|
|
862
|
+
# Check spam folder
|
|
863
|
+
# - Test emails sometimes flagged as spam
|
|
864
|
+
# - Add Cakemail to safe senders list
|
|
865
|
+
|
|
866
|
+
# Verify email address
|
|
867
|
+
$ echo "test@example.com" | grep -E '^[^@]+@[^@]+\.[^@]+$'
|
|
868
|
+
|
|
869
|
+
# Try different email address
|
|
870
|
+
$ cakemail campaigns test 790 -e alternate@example.com
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
### Merge Tags Not Replacing
|
|
874
|
+
|
|
875
|
+
**Problem:** Merge tags show as {{field_name}} instead of values
|
|
876
|
+
|
|
877
|
+
**Solutions:**
|
|
878
|
+
|
|
879
|
+
```bash
|
|
880
|
+
# Ensure test contact has data
|
|
881
|
+
$ cakemail contacts get 123 501 -f json | jq '{first_name, custom_attributes}'
|
|
882
|
+
|
|
883
|
+
# If empty, add data
|
|
884
|
+
$ cakemail contacts update 123 501 \
|
|
885
|
+
--first-name "John" \
|
|
886
|
+
-d '{"plan_type":"premium"}'
|
|
887
|
+
|
|
888
|
+
# Send test again
|
|
889
|
+
$ cakemail campaigns test 790 -e test@example.com
|
|
890
|
+
|
|
891
|
+
# Check merge tag syntax
|
|
892
|
+
# Correct: {{first_name}}
|
|
893
|
+
# Correct: {{custom_attributes.plan_type}}
|
|
894
|
+
# Wrong: {{firstName}} or {{plan_type}} (missing custom_attributes)
|
|
895
|
+
```
|
|
896
|
+
|
|
897
|
+
### Links Not Working
|
|
898
|
+
|
|
899
|
+
**Problem:** Links broken or not clickable
|
|
900
|
+
|
|
901
|
+
**Solutions:**
|
|
902
|
+
|
|
903
|
+
```bash
|
|
904
|
+
# Check HTML for proper link format
|
|
905
|
+
# Correct: <a href="https://example.com">Link</a>
|
|
906
|
+
# Wrong: <a href="example.com">Link</a> (missing protocol)
|
|
907
|
+
|
|
908
|
+
# Verify tracking enabled if needed
|
|
909
|
+
$ cakemail campaigns get 790 -f json | jq '.settings.track_clicks'
|
|
910
|
+
|
|
911
|
+
# Test without tracking
|
|
912
|
+
$ cakemail campaigns update 790 --no-track-clicks
|
|
913
|
+
$ cakemail campaigns test 790 -e test@example.com
|
|
914
|
+
|
|
915
|
+
# Re-enable tracking if it was issue
|
|
916
|
+
$ cakemail campaigns update 790 --track-clicks
|
|
917
|
+
```
|
|
918
|
+
|
|
919
|
+
### Images Not Loading
|
|
920
|
+
|
|
921
|
+
**Problem:** Images missing in test email
|
|
922
|
+
|
|
923
|
+
**Solutions:**
|
|
924
|
+
|
|
925
|
+
```bash
|
|
926
|
+
# Verify image URLs are absolute
|
|
927
|
+
# Correct: <img src="https://example.com/image.jpg">
|
|
928
|
+
# Wrong: <img src="/images/image.jpg"> (relative path)
|
|
929
|
+
|
|
930
|
+
# Check image URLs accessible
|
|
931
|
+
$ curl -I https://example.com/image.jpg
|
|
932
|
+
# Should return 200 OK
|
|
933
|
+
|
|
934
|
+
# Test in different clients
|
|
935
|
+
# - Some clients block images by default
|
|
936
|
+
# - Include "display images" instructions
|
|
937
|
+
|
|
938
|
+
# Verify image file size
|
|
939
|
+
# - Large images may fail to load
|
|
940
|
+
# - Recommended: < 100KB per image
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
### Mobile Layout Issues
|
|
944
|
+
|
|
945
|
+
**Problem:** Email doesn't display well on mobile
|
|
946
|
+
|
|
947
|
+
**Solutions:**
|
|
948
|
+
|
|
949
|
+
```bash
|
|
950
|
+
# Use responsive template
|
|
951
|
+
$ cakemail templates list -f json | jq '.data[] | select(.mobile_optimized == true)'
|
|
952
|
+
|
|
953
|
+
# Test mobile-specific version
|
|
954
|
+
$ cakemail campaigns test 790 -e your.phone@gmail.com
|
|
955
|
+
# Check on actual mobile device
|
|
956
|
+
|
|
957
|
+
# Verify viewport meta tag in HTML
|
|
958
|
+
# Required: <meta name="viewport" content="width=device-width, initial-scale=1">
|
|
959
|
+
|
|
960
|
+
# Use single-column layout
|
|
961
|
+
# Avoid multi-column designs for mobile
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
### Test Email Goes to Spam
|
|
965
|
+
|
|
966
|
+
**Problem:** Test emails landing in spam folder
|
|
967
|
+
|
|
968
|
+
**Solutions:**
|
|
969
|
+
|
|
970
|
+
```bash
|
|
971
|
+
# Verify sender authenticated
|
|
972
|
+
$ cakemail senders get 101 -f json | jq '{email, confirmed, dkim_enabled, spf_enabled}'
|
|
973
|
+
|
|
974
|
+
# Check subject line
|
|
975
|
+
# Avoid: ALL CAPS, excessive !!!, "FREE", "ACT NOW"
|
|
976
|
+
|
|
977
|
+
# Add company domain to safe senders
|
|
978
|
+
# In email client settings
|
|
979
|
+
|
|
980
|
+
# Test from different sender
|
|
981
|
+
$ cakemail campaigns update 790 --sender-id 102
|
|
982
|
+
$ cakemail campaigns test 790 -e test@example.com
|
|
983
|
+
```
|
|
984
|
+
|
|
985
|
+
## Best Practices Summary
|
|
986
|
+
|
|
987
|
+
1. **Always test before scheduling** - Never schedule without reviewing test email
|
|
988
|
+
2. **Test with real data** - Use realistic contact data for accurate previews
|
|
989
|
+
3. **Test multiple clients** - Verify appearance in Gmail, Outlook, Apple Mail
|
|
990
|
+
4. **Test on mobile** - Ensure responsive design works on phones
|
|
991
|
+
5. **Test all links** - Click every link to verify functionality
|
|
992
|
+
6. **Test merge tags** - Verify personalization with actual contact data
|
|
993
|
+
7. **Get stakeholder approval** - Send tests to editors, designers, managers
|
|
994
|
+
8. **Document test results** - Keep log of tests and issues found
|
|
995
|
+
9. **Iterate and retest** - Test after every significant change
|
|
996
|
+
10. **Use test distribution lists** - Create reusable test email groups
|
|
997
|
+
|