Custom Attributes
Extend contact records with custom fields to store business-specific data beyond standard email and name fields.
Overview
Custom attributes allow you to:
- Store unlimited additional contact data
- Track customer preferences and behavior
- Enable advanced segmentation
- Personalize campaigns with custom data
- Integrate with your business systems
- Build comprehensive customer profiles
Custom attributes are the key to making Cakemail work for your specific business needs.
Quick Start
Create Your First Attribute
$ cakemail attributes create 123 -n "plan_type" -t "text"
Output:
✓ Custom attribute created: plan_type
Name: plan_type
Type: text
List: 123
Add Contact with Custom Data
$ cakemail contacts add 123 \
-e "customer@example.com" \
-f "Jane" \
-l "Doe" \
-d '{"plan_type":"premium"}'
View Attributes
$ cakemail attributes list 123
Output:
┌──────────────────┬──────────┬─────────────────────┐
│ Name │ Type │ Created │
├──────────────────┼──────────┼─────────────────────┤
│ plan_type │ text │ 2024-01-15 10:30:00 │
│ signup_date │ date │ 2024-02-01 14:20:00 │
│ lifetime_value │ number │ 2024-02-15 09:00:00 │
│ is_vip │ boolean │ 2024-03-01 11:45:00 │
└──────────────────┴──────────┴─────────────────────┘
Attribute Types
Text Attributes
Store string values like names, categories, or IDs.
Create:
$ cakemail attributes create 123 -n "plan_type" -t "text"
$ cakemail attributes create 123 -n "customer_id" -t "text"
$ cakemail attributes create 123 -n "company_name" -t "text"
Use cases:
- Plan tiers (free, basic, premium, enterprise)
- Customer segments (new, active, lapsed)
- Industry categories (technology, retail, finance)
- Product preferences (red, blue, green)
- External system IDs
Example values:
{
"plan_type": "premium",
"customer_id": "CUST-12345",
"company_name": "Acme Corporation",
"industry": "Technology",
"preferred_color": "blue"
}
Number Attributes
Store numeric values like counts, amounts, or scores.
Create:
$ cakemail attributes create 123 -n "purchase_count" -t "number"
$ cakemail attributes create 123 -n "lifetime_value" -t "number"
$ cakemail attributes create 123 -n "engagement_score" -t "number"
Use cases:
- Purchase counts
- Lifetime value (dollars)
- Engagement scores
- Account age (days)
- Product quantities
Example values:
{
"purchase_count": 15,
"lifetime_value": 2499.99,
"engagement_score": 87,
"account_age_days": 365,
"cart_items": 3
}
Date Attributes
Store dates in ISO format (YYYY-MM-DD).
Create:
$ cakemail attributes create 123 -n "signup_date" -t "date"
$ cakemail attributes create 123 -n "last_purchase" -t "date"
$ cakemail attributes create 123 -n "trial_ends" -t "date"
Use cases:
- Signup/registration dates
- Last purchase dates
- Trial expiration dates
- Birthday/anniversary dates
- Renewal dates
Example values:
{
"signup_date": "2024-01-15",
"last_purchase": "2024-03-10",
"trial_ends": "2024-04-15",
"birthday": "1990-06-15",
"renewal_date": "2024-12-31"
}
Boolean Attributes
Store true/false flags.
Create:
$ cakemail attributes create 123 -n "is_vip" -t "boolean"
$ cakemail attributes create 123 -n "opted_in_sms" -t "boolean"
$ cakemail attributes create 123 -n "email_verified" -t "boolean"
Use cases:
- VIP status
- Feature flags
- Opt-in preferences
- Verification status
- Active/inactive indicators
Example values:
{
"is_vip": true,
"opted_in_sms": false,
"email_verified": true,
"marketing_consent": true,
"account_locked": false
}
Attribute Naming
Best Naming Practices
Good names:
$ cakemail attributes create 123 -n "plan_type" -t "text" # Clear purpose
$ cakemail attributes create 123 -n "last_login_date" -t "date" # Descriptive
$ cakemail attributes create 123 -n "is_premium" -t "boolean" # Clear boolean
$ cakemail attributes create 123 -n "total_spent" -t "number" # Clear metric
Avoid:
$ cakemail attributes create 123 -n "pt" -t "text" # Too short
$ cakemail attributes create 123 -n "Plan Type" -t "text" # Spaces
$ cakemail attributes create 123 -n "PLAN" -t "text" # All caps
$ cakemail attributes create 123 -n "thePlanTypeForCustomer" -t "text" # Too verbose
Naming Conventions
Use snake_case:
plan_type # ✓
lifetime_value # ✓
last_purchase_date # ✓
is_vip # ✓
Not camelCase or spaces:
planType # ✗
lifetimeValue # ✗
"last purchase" # ✗
"Is VIP" # ✗
Boolean prefix:
is_vip # ✓ Clear it's boolean
has_subscription # ✓ Clear it's boolean
email_verified # ✓ Clear it's boolean
vip # ✗ Not obvious it's boolean
subscription # ✗ Not obvious it's boolean
Attribute Workflows
Workflow 1: Customer Data Setup
#!/bin/bash
# setup-customer-attributes.sh
LIST_ID=123
echo "=== Setting Up Customer Attributes ==="
echo ""
# Basic info
echo "Creating basic customer attributes..."
cakemail attributes create $LIST_ID -n "customer_id" -t "text"
cakemail attributes create $LIST_ID -n "company_name" -t "text"
cakemail attributes create $LIST_ID -n "industry" -t "text"
cakemail attributes create $LIST_ID -n "company_size" -t "text"
# Subscription
echo "Creating subscription attributes..."
cakemail attributes create $LIST_ID -n "plan_type" -t "text"
cakemail attributes create $LIST_ID -n "signup_date" -t "date"
cakemail attributes create $LIST_ID -n "trial_ends" -t "date"
cakemail attributes create $LIST_ID -n "is_paying" -t "boolean"
# Engagement
echo "Creating engagement attributes..."
cakemail attributes create $LIST_ID -n "last_login_date" -t "date"
cakemail attributes create $LIST_ID -n "login_count" -t "number"
cakemail attributes create $LIST_ID -n "feature_usage_score" -t "number"
# Financial
echo "Creating financial attributes..."
cakemail attributes create $LIST_ID -n "lifetime_value" -t "number"
cakemail attributes create $LIST_ID -n "purchase_count" -t "number"
cakemail attributes create $LIST_ID -n "last_purchase_date" -t "date"
cakemail attributes create $LIST_ID -n "average_order_value" -t "number"
echo ""
echo "✓ Attribute setup complete"
echo ""
# Show all attributes
cakemail attributes list $LIST_ID
Workflow 2: E-commerce Attributes
#!/bin/bash
# setup-ecommerce-attributes.sh
LIST_ID=123
echo "=== E-commerce Attribute Setup ==="
echo ""
# Purchase behavior
cakemail attributes create $LIST_ID -n "total_orders" -t "number"
cakemail attributes create $LIST_ID -n "total_spent" -t "number"
cakemail attributes create $LIST_ID -n "average_order_value" -t "number"
cakemail attributes create $LIST_ID -n "last_order_date" -t "date"
cakemail attributes create $LIST_ID -n "first_order_date" -t "date"
# Preferences
cakemail attributes create $LIST_ID -n "favorite_category" -t "text"
cakemail attributes create $LIST_ID -n "preferred_brand" -t "text"
cakemail attributes create $LIST_ID -n "size_preference" -t "text"
# Loyalty
cakemail attributes create $LIST_ID -n "loyalty_points" -t "number"
cakemail attributes create $LIST_ID -n "loyalty_tier" -t "text"
cakemail attributes create $LIST_ID -n "is_vip" -t "boolean"
# Cart behavior
cakemail attributes create $LIST_ID -n "cart_abandoned_date" -t "date"
cakemail attributes create $LIST_ID -n "cart_value" -t "number"
cakemail attributes create $LIST_ID -n "has_active_cart" -t "boolean"
echo "✓ E-commerce attributes created"
Workflow 3: SaaS Attributes
#!/bin/bash
# setup-saas-attributes.sh
LIST_ID=123
echo "=== SaaS Attribute Setup ==="
echo ""
# Account
cakemail attributes create $LIST_ID -n "account_id" -t "text"
cakemail attributes create $LIST_ID -n "plan_name" -t "text"
cakemail attributes create $LIST_ID -n "mrr" -t "number"
cakemail attributes create $LIST_ID -n "arr" -t "number"
# Subscription lifecycle
cakemail attributes create $LIST_ID -n "trial_start_date" -t "date"
cakemail attributes create $LIST_ID -n "trial_end_date" -t "date"
cakemail attributes create $LIST_ID -n "subscription_start" -t "date"
cakemail attributes create $LIST_ID -n "next_billing_date" -t "date"
cakemail attributes create $LIST_ID -n "is_trial" -t "boolean"
cakemail attributes create $LIST_ID -n "is_paying" -t "boolean"
# Usage
cakemail attributes create $LIST_ID -n "last_login" -t "date"
cakemail attributes create $LIST_ID -n "login_count_30d" -t "number"
cakemail attributes create $LIST_ID -n "feature_adoption_score" -t "number"
cakemail attributes create $LIST_ID -n "active_users" -t "number"
# Health
cakemail attributes create $LIST_ID -n "health_score" -t "number"
cakemail attributes create $LIST_ID -n "churn_risk" -t "text"
cakemail attributes create $LIST_ID -n "support_tickets_30d" -t "number"
echo "✓ SaaS attributes created"
Workflow 4: Attribute Audit
#!/bin/bash
# audit-attributes.sh
LIST_ID=123
echo "=== Attribute Audit ==="
echo ""
# Get all attributes
ATTRIBUTES=$(cakemail attributes list $LIST_ID -f json | jq -r '.data[] | "\(.name):\(.type)"')
echo "Attribute | Type | Usage (%)"
echo "----------|------|----------"
# Check usage for each attribute
for ATTR in $ATTRIBUTES; do
NAME=$(echo "$ATTR" | cut -d: -f1)
TYPE=$(echo "$ATTR" | cut -d: -f2)
# Get contacts with this attribute set
TOTAL=$(cakemail contacts list $LIST_ID -f json | jq '.count')
# Note: This is simplified - actual implementation would need to check each contact
# For demonstration purposes
USAGE="~%"
printf "%-20s | %-8s | %s\n" "$NAME" "$TYPE" "$USAGE"
done
echo ""
echo "Review attributes with low usage for potential removal"
Workflow 5: Attribute Migration
#!/bin/bash
# migrate-attributes.sh
SOURCE_LIST=123
TARGET_LIST=124
echo "=== Migrating Attributes ==="
echo "From: List $SOURCE_LIST"
echo "To: List $TARGET_LIST"
echo ""
# Get source attributes
ATTRIBUTES=$(cakemail attributes list $SOURCE_LIST -f json)
echo "$ATTRIBUTES" | jq -r '.data[] | "\(.name):\(.type)"' | while IFS=: read NAME TYPE; do
echo "Creating: $NAME ($TYPE)"
# Create in target list
cakemail attributes create $TARGET_LIST -n "$NAME" -t "$TYPE" 2>/dev/null
if [ $? -eq 0 ]; then
echo " ✓ Created"
else
echo " ⚠️ Already exists or error"
fi
done
echo ""
echo "✓ Attribute migration complete"
Using Attributes with Contacts
Add Contact with Attributes
$ cakemail contacts add 123 \
-e "customer@example.com" \
-f "Jane" \
-l "Doe" \
-d '{
"plan_type": "premium",
"signup_date": "2024-03-15",
"is_vip": true,
"lifetime_value": 599.99,
"purchase_count": 8
}'
Update Contact Attributes
# Update single attribute
$ cakemail contacts update 123 501 -d '{"plan_type":"enterprise"}'
# Update multiple attributes
$ cakemail contacts update 123 501 -d '{
"plan_type": "enterprise",
"is_vip": true,
"lifetime_value": 1299.99
}'
Query by Attributes
# Find premium users
$ cakemail contacts list 123 --filter "custom_attributes.plan_type==premium"
# Find VIP customers
$ cakemail contacts list 123 --filter "custom_attributes.is_vip==true"
# Find high-value customers
$ cakemail contacts list 123 --filter "custom_attributes.lifetime_value>=1000"
# Find recent signups
$ cakemail contacts list 123 --filter "custom_attributes.signup_date>=2024-03-01"
Segmentation with Attributes
Create Segments Based on Attributes
# Premium plan segment
$ cakemail segments create 123 -n "Premium Users" -c '{
"match": "all",
"rules": [
{"field": "custom_attributes.plan_type", "operator": "equals", "value": "premium"}
]
}'
# High-value customers
$ cakemail segments create 123 -n "High Value" -c '{
"match": "all",
"rules": [
{"field": "custom_attributes.lifetime_value", "operator": "greater_than", "value": "1000"}
]
}'
# At-risk trial users
$ cakemail segments create 123 -n "Trial Ending Soon" -c '{
"match": "all",
"rules": [
{"field": "custom_attributes.is_trial", "operator": "equals", "value": "true"},
{"field": "custom_attributes.trial_ends", "operator": "less_than", "value": "2024-04-01"}
]
}'
# Engaged VIPs
$ cakemail segments create 123 -n "Engaged VIPs" -c '{
"match": "all",
"rules": [
{"field": "custom_attributes.is_vip", "operator": "equals", "value": "true"},
{"field": "last_open_date", "operator": "greater_than", "value": "2024-03-01"}
]
}'
Campaign Personalization
Use Attributes in Campaigns
Campaign HTML with merge tags:
<p>Hi {{first_name}},</p>
<p>As a {{custom_attributes.plan_type}} member, you have access to:</p>
{{#if custom_attributes.is_vip}}
<p><strong>VIP Benefits:</strong></p>
<ul>
<li>Priority Support</li>
<li>Exclusive Features</li>
<li>Early Access</li>
</ul>
{{/if}}
<p>You've been with us since {{custom_attributes.signup_date}}.</p>
<p>Your lifetime savings: ${{custom_attributes.lifetime_value}}</p>
<p>Thanks for {{custom_attributes.purchase_count}} purchases!</p>
Conditional Content
{{#if custom_attributes.plan_type == "free"}}
<div class="upgrade-prompt">
<h2>Upgrade to Premium</h2>
<p>Get more features for just $9.99/month</p>
<a href="https://example.com/upgrade">Upgrade Now</a>
</div>
{{/if}}
{{#if custom_attributes.cart_abandoned_date}}
<div class="cart-reminder">
<h2>You Left Items in Your Cart</h2>
<p>Complete your purchase and save {{custom_attributes.cart_value}}!</p>
<a href="https://example.com/cart">Return to Cart</a>
</div>
{{/if}}
Attribute Best Practices
1. Plan Schema First
# Document your attribute schema
cat > attribute-schema.md << 'EOF'
# Customer Attributes Schema
## Account
- customer_id (text): External CRM ID
- account_type (text): individual | business
- signup_date (date): Registration date
## Subscription
- plan_type (text): free | basic | premium | enterprise
- is_paying (boolean): Active paid subscription
- mrr (number): Monthly recurring revenue
## Engagement
- last_login (date): Last login date
- login_count_30d (number): Logins in last 30 days
- health_score (number): 0-100 engagement score
## Financial
- lifetime_value (number): Total revenue
- purchase_count (number): Total orders
- average_order_value (number): AOV
EOF
2. Use Consistent Types
# All dates as date type
$ cakemail attributes create 123 -n "signup_date" -t "date"
$ cakemail attributes create 123 -n "last_purchase" -t "date"
$ cakemail attributes create 123 -n "trial_ends" -t "date"
# All monetary values as number
$ cakemail attributes create 123 -n "lifetime_value" -t "number"
$ cakemail attributes create 123 -n "monthly_spend" -t "number"
$ cakemail attributes create 123 -n "cart_value" -t "number"
# All flags as boolean
$ cakemail attributes create 123 -n "is_vip" -t "boolean"
$ cakemail attributes create 123 -n "email_verified" -t "boolean"
$ cakemail attributes create 123 -n "marketing_consent" -t "boolean"
3. Validate Data Before Setting
#!/bin/bash
# validate-and-set.sh
LIST_ID=123
CONTACT_ID=501
PLAN="$1"
# Validate plan type
VALID_PLANS=("free" "basic" "premium" "enterprise")
if [[ ! " ${VALID_PLANS[@]} " =~ " ${PLAN} " ]]; then
echo "❌ Invalid plan: $PLAN"
echo "Valid plans: ${VALID_PLANS[@]}"
exit 1
fi
# Set attribute
cakemail contacts update $LIST_ID $CONTACT_ID -d "{\"plan_type\":\"$PLAN\"}"
echo "✓ Plan set to: $PLAN"
4. Keep Attributes Synchronized
#!/bin/bash
# sync-from-crm.sh
LIST_ID=123
echo "=== Syncing from CRM ==="
echo ""
# Fetch from your CRM (example)
CUSTOMERS=$(curl -s "https://api.yourcrm.com/customers")
echo "$CUSTOMERS" | jq -c '.[]' | while read CUSTOMER; do
EMAIL=$(echo "$CUSTOMER" | jq -r '.email')
PLAN=$(echo "$CUSTOMER" | jq -r '.plan')
LTV=$(echo "$CUSTOMER" | jq -r '.lifetime_value')
LAST_PURCHASE=$(echo "$CUSTOMER" | jq -r '.last_purchase_date')
# Find contact
CONTACTS=$(cakemail contacts list $LIST_ID --filter "email==$EMAIL" -f json)
CONTACT_ID=$(echo "$CONTACTS" | jq -r '.data[0].id')
if [ "$CONTACT_ID" != "null" ]; then
# Update attributes
cakemail contacts update $LIST_ID $CONTACT_ID -d "{
\"plan_type\": \"$PLAN\",
\"lifetime_value\": $LTV,
\"last_purchase_date\": \"$LAST_PURCHASE\"
}"
echo " Synced: $EMAIL"
fi
done
echo ""
echo "✓ CRM sync complete"
5. Remove Unused Attributes
#!/bin/bash
# cleanup-unused.sh
LIST_ID=123
echo "=== Cleaning Up Unused Attributes ==="
echo ""
# List of deprecated attributes
DEPRECATED=(
"old_field"
"legacy_score"
"temp_attribute"
)
for ATTR in "${DEPRECATED[@]}"; do
echo "Removing: $ATTR"
cakemail attributes delete $LIST_ID $ATTR --force
done
echo ""
echo "✓ Cleanup complete"
Troubleshooting
Attribute Not Appearing
Problem: Created attribute but it's not showing
Solution:
# Verify attribute was created
$ cakemail attributes list 123
# Check specific attribute
$ cakemail attributes get 123 plan_type
# If not found, recreate
$ cakemail attributes create 123 -n "plan_type" -t "text"
Cannot Set Attribute Value
Problem: Attribute value not saving on contact
Solutions:
# 1. Ensure attribute exists
$ cakemail attributes list 123
# 2. Check data type matches
$ cakemail attributes get 123 lifetime_value
# If type is "number", use number not string:
$ cakemail contacts update 123 501 -d '{"lifetime_value":599.99}' # ✓
$ cakemail contacts update 123 501 -d '{"lifetime_value":"599.99"}' # ✗
# 3. Check JSON format
$ cakemail contacts update 123 501 -d '{"plan":"premium"}' # ✓ Valid JSON
$ cakemail contacts update 123 501 -d '{plan:premium}' # ✗ Invalid JSON
Wrong Data Type
Problem: Created attribute with wrong type
Solution:
# Type cannot be changed
# Must delete and recreate
# 1. Export contacts with old attribute
$ cakemail contacts export 123
# 2. Delete old attribute
$ cakemail attributes delete 123 old_name --force
# 3. Create with correct type
$ cakemail attributes create 123 -n "new_name" -t "number"
# 4. Re-import contacts with new attribute
# (Update CSV with new column)
$ cakemail contacts import 123 --file updated.csv
Date Format Issues
Problem: Dates not saving correctly
Solution:
# Use ISO format: YYYY-MM-DD
$ cakemail contacts update 123 501 -d '{"signup_date":"2024-03-15"}' # ✓
# Wrong formats:
# "03/15/2024" # ✗ US format
# "15/03/2024" # ✗ European format
# "March 15, 2024" # ✗ Text format
# Convert if needed
DATE="03/15/2024"
ISO_DATE=$(date -d "$DATE" +%Y-%m-%d) # Converts to 2024-03-15
Best Practices Summary
- Plan schema first - Design attributes before creating
- Use descriptive names - Clear, self-explanatory names
- Choose correct types - Match data type to usage
- Validate input - Check values before setting
- Document attributes - Keep schema documentation
- Consistent naming - Use snake_case
- Sync regularly - Keep attributes updated from source systems
- Remove unused - Delete deprecated attributes
- Test thoroughly - Verify attributes work in campaigns
- Monitor usage - Track which attributes are actually used