Skip to content

d3cline/MCPigeon

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MC Pigeon

MC Pigeon

MCP-native, IMAP-first email campaigns. Markdown in → thousands out. Drive everything from an AI agent (VS Code or any MCP client). Tracks opens/clicks, appends to your Sent via IMAP, and handles bounces/replies.

  • Stack: Python 3.13 • Django 5+ • Celery 5+ • Postgres (recommended)
  • Core surfaces: MCP tools (primary), Django Admin, CLI.

📹➡️Demo Video Here➡️📹


1) Install

git clone <repo_url> mcpigeon
cd mcpigeon
python3 -m venv env && source env/bin/activate
pip install -r requirements.in

Minimal settings in MCPigeon/settings.py:

# Public base for tracked URLs & pixel
CAMPAIGNS_PUBLIC_BASE_URL = "https://your.app"  # required by template tags

# Celery (example: Redis)
CELERY_BROKER_URL = "redis://localhost:6379/0"
CELERY_RESULT_BACKEND = "redis://localhost:6379/0"

# MCP recipient ingest per-call cap (default 1000)
MCP_MAX_RECIPIENT_BATCH = 1000

(Template tags build click/pixel URLs off CAMPAIGNS_PUBLIC_BASE_URL.)

Database & superuser:

python manage.py migrate
python manage.py createsuperuser

Run web + worker:

python manage.py runserver 0.0.0.0:8000
# new shell
export DJANGO_SETTINGS_MODULE=MCPigeon.settings
celery -A campaigns.sender:app worker -l info

The task pipeline is idempotent and retries on transient DB errors; it sends a failure report email when a run completes.


2) Model shape (you’ll see these in Admin)

  • Mailbox: SMTP/IMAP creds + sent_folder, bounce_folder.
  • Campaign: name, subject, mailbox, template_markdown, status.
  • Recipient: unique per (campaign,email), optional name, unsubscribed, meta.
  • MessageInstance: one per recipient send; holds message_id, timestamps, click count.
  • Link / LinkClick / OpenEvent / DeliveryEvent: tracking artifacts.

3) MCP (the primary interface)

This repo exposes MCP tools you can mount in your MCP host (VS Code, Claude Desktop, Cursor/Cline/Continue, etc.). Tools:

  • mailboxes — CRUD + verify creds + optional remote provisioning.
  • campaigns — CRUD + send, status, list_recipients, add_recipient, clone, post_recipients (bulk).
  • campaign_mailbox — assign/switch a campaign’s mailbox.

Mounting (typical local config):

  • Command: your MCP host’s “add local tool/server” pointing at the Python that imports campaigns.mcp (stdio).
  • Env: DJANGO_SETTINGS_MODULE=MCPigeon.settings (and your Django env vars).
  • CWD: repo root.

Common MCP calls

Create a mailbox, then verify creds

{"tool":"mailboxes","action":"create","payload":{
  "name":"Sales","from_name":"Sales","from_email":"sales@your.app",
  "smtp_host":"smtp.your.app","smtp_port":587,"smtp_starttls":true,
  "smtp_username":"sales@your.app","smtp_password":"***",
  "imap_host":"imap.your.app","imap_port":993,"imap_ssl":true,
  "imap_username":"sales@your.app","imap_password":"***",
  "sent_folder":"Sent","bounce_folder":"INBOX"
}}
{"tool":"mailboxes","action":"verify","payload":{"id":1}}

(Verify attempts real SMTP/IMAP logins and returns pass/fail + errors.)

Create a campaign

{"tool":"campaigns","action":"create","payload":{
  "name":"September Promo",
  "subject":"Save big this month",
  "mailbox_id":1,
  "template_markdown":"Hey {{ recipient.name|default:\"there\" }} — check this out!"
}}

Bulk-import recipients (strings or objects)

{"tool":"campaigns","action":"post_recipients","payload":{
  "campaign_id":123,
  "on_conflict":"update_name",
  "recipients":[
    "Ada Lovelace <ada@ex.com>",
    {"email":"grace@ex.com","name":"Grace Hopper"},
    "alan@ex.com"
  ]
}}
  • Accepts up to MCP_MAX_RECIPIENT_BATCH per call; returns remaining for pagination.
  • Validates emails; dedupes within the batch; can update names on conflicts.

Send (queued via Celery)

{"tool":"campaigns","action":"send","payload":{"campaign_id":123}}

Check progress:

{"tool":"campaigns","action":"status","payload":{"campaign_id":123}}

(Status reports sent/opened/bounced/clicks + last event.)

Switch a campaign’s mailbox

{"tool":"campaign_mailbox","action":"assign","payload":{"campaign_id":123,"mailbox_id":2}}

Implementation note: each recipient gets a stable RFC5322 Message-ID like <uuid.campaignId.recipientId@domain>, which the IMAP sync uses to reconcile replies/bounces.


4) Django Admin (supporting surface)

  • Add a Mailbox with working SMTP/IMAP creds.
  • Create a Campaign (Markdown body).
  • Add Recipients (or use MCP bulk ingest).
  • Enqueue/send from Admin actions or use MCP/CLI. (Status and events are visible via related models.)

5) CLI (supporting surface)

Send (sync or enqueue)

python manage.py campaign_send --campaign 123
python manage.py campaign_send --campaign 123 --dry-run
python manage.py campaign_send --name "September Promo" --enqueue --batch-size 200 --sleep 1.5
  • --enqueue splits recipients and schedules chunk tasks.

Enqueue directly

python manage.py campaign_enqueue --campaign 123 --chunk-size 300

(Uses send_campaign_chunk.delay per chunk.)

IMAP sync (bounces/replies)

python manage.py campaign_imap_sync
  • Logs into each campaign mailbox’s bounce_folder, processes UNSEEN, marks \Seen.
  • Classifies BOUNCE/DEFERRED/REPLY; sets bounced_at and records DeliveryEvent.
  • Matches messages by our Message-ID pattern <campaignId.recipientId.rnd@domain>.

6) Writing templates (Markdown + tags)

Enable the tags by keeping campaigns/templatetags/campaigns.py in the app. Use:

Hey {{ recipient.name|default:"there" }}!

[Open link]({% track_url campaign recipient "https://example.com" %})
<img src="{% tracking_pixel message %}" width="1" height="1" style="display:none" alt="">
  • {% track_url %} rewrites to a tracked redirect under CAMPAIGNS_PUBLIC_BASE_URL.
  • {% tracking_pixel %} emits the 1×1 open-tracking URL.

7) Notes on sending & resilience

  • Task campaigns.send_campaign is idempotent; re-runs skip already-sent recipients.
  • Per-recipient failures don’t abort the run; a summary email is sent at the end.
  • On DB hiccups, the task retries with backoff/jitter.

8) Deliverability (bare minimum)

Set up SPF/DKIM/DMARC, warm up with smaller batches + sleeps, include unsubscribe, and honor bounces/unsubs. (Clicks/opens depend on client behavior.)


License

Apache-2.0


Mail stays where it belongs: your mailbox. Your agent runs the show.

About

MCP Email Campaign Sender

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages