Data Analytics project 19
Email Campaign Analysis Project with Python
Build a complete email campaign analysis portfolio project with documented metrics, reproducible Python code, validation checks, and responsible interpretation.
Explore Data Analytics training in VizagView all project ideas
Business question
How should email delivery and downstream engagement rates be calculated with consistent denominators?
Dataset and grain
Forty synthetic email campaigns with sent, bounced, delivered, unique opens, unique clicks, conversions, and unsubscribes.
Requirements
Python 3.10 or later with numpy and pandas installed.
Method and validation checks
Reconcile delivered as sent minus bounced, calculate delivery rate from sent, and calculate open, click, conversion, and unsubscribe rates from delivered; calculate click-to-open separately.
- Sent equals delivered plus bounced
- Unique clicks never exceed unique opens in the demo
- Every rate states its denominator
- Open rate limitations remain visible
Complete Python code
Save the code as da_email_campaign_analysis.py. Review the stated model and field assumptions before using another dataset.
"""Calculate delivered-email funnel metrics from synthetic campaign data."""
from __future__ import annotations
import numpy as np
import pandas as pd
def make_demo_email_campaigns(n: int = 40, seed: int = 42) -> pd.DataFrame:
rng = np.random.default_rng(seed)
sent = rng.integers(8_000, 90_000, n)
bounced = rng.binomial(sent, rng.uniform(0.004, 0.025, n))
delivered = sent - bounced
opens = rng.binomial(delivered, rng.uniform(0.18, 0.52, n))
clicks = rng.binomial(opens, rng.uniform(0.035, 0.18, n))
conversions = rng.binomial(clicks, rng.uniform(0.04, 0.22, n))
unsubscribes = rng.binomial(delivered, rng.uniform(0.0002, 0.003, n))
return pd.DataFrame({"campaign_id": [f"EM{i:03d}" for i in range(1, n + 1)], "sent": sent, "bounced": bounced, "delivered": delivered, "unique_opens": opens, "unique_clicks": clicks, "conversions": conversions, "unsubscribes": unsubscribes})
def analyse_email(data: pd.DataFrame) -> pd.DataFrame:
result = data.copy()
denominator = result["delivered"].replace(0, np.nan)
result["delivery_rate"] = result["delivered"] / result["sent"]
result["open_rate"] = result["unique_opens"] / denominator
result["click_rate"] = result["unique_clicks"] / denominator
result["click_to_open_rate"] = result["unique_clicks"] / result["unique_opens"].replace(0, np.nan)
result["conversion_rate"] = result["conversions"] / denominator
result["unsubscribe_rate"] = result["unsubscribes"] / denominator
return result
def main() -> None:
result = analyse_email(make_demo_email_campaigns())
metrics = ["delivery_rate", "open_rate", "click_rate", "click_to_open_rate", "conversion_rate", "unsubscribe_rate"]
print(result[metrics].mean().round(4).to_string())
print("Open rates can be distorted by privacy features; prefer clicks and downstream outcomes.")
if __name__ == "__main__":
main()
Build and run the project
Run python da_email_campaign_analysis.py to calculate delivery, open, click, conversion, and unsubscribe metrics.
- Confirm the source grain and field definitions.
- Reconcile record counts and additive totals.
- Validate rate denominators and date filters.
- Review outliers and missing values.
- Read the interpretation limits before sharing conclusions.
Expected analytical output
Campaign-level delivery, open, click, click-to-open, conversion, and unsubscribe rates plus mean metrics.
Interpretation and responsible-use limits
Mailbox privacy features can inflate or obscure opens. Prefer clicks and verified downstream outcomes, and comply with consent, unsubscribe, retention, and platform rules.
Ways to extend the project
Add audience segment, subject test, send time, holdout groups, revenue and margin, deliverability by domain, and confidence intervals.
Continue learning Data Analytics
Try the next project, return to the Softenant project library, or explore the Data Analytics course in Vizag for guided SQL, Excel, Power BI, Python, dashboard, and portfolio practice.