Politician Email Automation - Implementation Plan
Overview
Automatically send pre-written emails to politicians on behalf of pledge signers, using a transactional email service with Reply-To set to the constituent's email address.
Platform Recommendation
Quick Comparison
| Platform | Free Tier | Paid | API Quality | Deliverability | Best For |
|---|---|---|---|---|---|
| Postmark | None | $15/mo for 10k | Excellent | Best-in-class | Transactional to strict filters |
| Mailgun | 5k/mo (3 months) | ~$0.80/1k emails | Excellent | Very good | Developer-friendly, cheap |
| SendGrid | 100/day | $20/mo for 50k | Good | Mixed (shared IPs) | High volume marketing |
| Amazon SES | 62k/mo (if in EC2) | $0.10/1k | Good | Good | AWS shops |
Recommendation: Postmark or Mailgun
Why not SendGrid for this use case:
- Free/low tiers share IP pools with spammers → deliverability issues
- Government email systems have aggressive spam filters
- You're sending to .gov and .ca.gov addresses — deliverability matters more than volume
Postmark is purpose-built for transactional email and has the best reputation for reaching strict inboxes (banks, government, enterprise). $15/mo covers 10k emails which is way more than needed.
Mailgun is the budget option with excellent API. Pay-as-you-go after trial is very cheap.
For emails to politicians where you want maximum "did it actually arrive" confidence: Postmark.
Implementation Plan
Phase 1: Email Service Setup (API-driven)
1.1 Create Postmark Account - Sign up at postmarkapp.com - Create a "Server" (their term for a project/environment) - Get API token (Server API Token)
1.2 Domain Verification (DNS) Add these records to californiaforever.com DNS: - SPF record (TXT) - DKIM record (TXT) - Return-Path CNAME
Postmark provides exact values in dashboard. Can be done via registrar or Flywheel if DNS is there.
1.3 Sender Signature
Verify pledges@californiaforever.com (or similar) as authorized sender.
Phase 2: WordPress Integration
2.1 Create Integration File
New file: inc/integrations/politician-email-sender.php
/**
* Politician Email Sender
* Sends automated emails to politicians via Postmark API
*/
// API credentials (store in wp-config.php)
// define('POSTMARK_API_TOKEN', 'xxxxx');
/**
* Send politician email on behalf of pledge signer
*/
function cf_send_politician_email( $args ) {
$defaults = array(
'constituent_name' => '',
'constituent_email' => '',
'constituent_zip' => '',
'politician_name' => '',
'politician_email' => '',
'politician_title' => '',
);
$args = wp_parse_args( $args, $defaults );
// Build email
$subject = 'Support California Forever - Break Ground in 2026';
$body = sprintf(
"Dear %s,\n\n" .
"I am writing to express my support for California Forever and the East Solano Plan...\n\n" .
"... [rest of template] ...\n\n" .
"Sincerely,\n" .
"%s\n" .
"%s\n" .
"%s",
$args['politician_name'],
$args['constituent_name'],
$args['constituent_email'],
$args['constituent_zip']
);
// Postmark API call
$response = wp_remote_post(
'https://api.postmarkapp.com/email',
array(
'headers' => array(
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'X-Postmark-Server-Token' => POSTMARK_API_TOKEN,
),
'body' => wp_json_encode( array(
'From' => 'California Forever Pledges <pledges@californiaforever.com>',
'To' => $args['politician_email'],
'ReplyTo' => $args['constituent_email'],
'Subject' => $subject,
'TextBody' => $body,
'Tag' => 'politician-outreach',
'TrackOpens' => false, // Don't track - feels surveillance-y
'TrackLinks' => 'None',
'MessageStream' => 'outbound',
) ),
)
);
// Log result
$result = json_decode( wp_remote_retrieve_body( $response ), true );
return array(
'success' => ! is_wp_error( $response ) && isset( $result['MessageID'] ),
'message_id' => $result['MessageID'] ?? null,
'error' => $result['Message'] ?? null,
);
}
2.2 Hook into Gravity Forms Submission
Modify existing californiaforever_create_pledge_from_gf() in pledge-signers.php:
// After creating pledge signer post...
// Look up politician by zip
$politician = cf_get_politician_by_zip( $zip_code );
if ( $politician && ! empty( $email ) ) {
$email_result = cf_send_politician_email( array(
'constituent_name' => trim( $first_name . ' ' . $last_name ),
'constituent_email' => $email,
'constituent_zip' => $zip_code,
'politician_name' => $politician['name'],
'politician_email' => $politician['email'],
'politician_title' => $politician['title'],
) );
// Store result on pledge signer post
update_post_meta( $post_id, '_politician_email_sent', $email_result['success'] ? 'yes' : 'no' );
update_post_meta( $post_id, '_politician_email_id', $email_result['message_id'] );
}
2.3 Extract Politician Lookup
Move $politician_map from module template to shared function:
/**
* Get politician data by zip code
*/
function cf_get_politician_by_zip( $zip_code ) {
$politician_map = array(
'94510' => array(
'name' => 'Senator Maria Gonzalez',
'email' => 'maria.gonzalez@senate.ca.gov',
'title' => 'State Senator, District 3',
),
// ... rest of map
);
$zip_code = preg_replace( '/[^0-9]/', '', $zip_code );
if ( strlen( $zip_code ) === 5 && isset( $politician_map[ $zip_code ] ) ) {
return $politician_map[ $zip_code ];
}
return null;
}
Phase 3: Thank You Page Update
Current behavior: Shows copy/paste email template
New behavior: - If email was sent → "Your message has been sent to [Politician Name]!" - If no zip match → Current fallback (find your representative link)
Pass success state via URL parameter: ?zip=94533&sent=1
Phase 4: Admin Visibility
4.1 Add column to Pledge Signers list
| Name | Organization | Status | Email Sent | Date Signed |
|---|---|---|---|---|
| John Doe | Acme Corp | Approved | ✓ Sent | Jan 15 |
| Jane Smith | — | Pending | ✗ No match | Jan 14 |
4.2 Store metadata
_politician_email_sent→ 'yes' / 'no' / 'no_match'_politician_email_id→ Postmark message ID (for debugging)_politician_email_to→ Which politician received it
Templates
No fancy templates needed.
Postmark (and most transactional services) support:
- Plain text (TextBody) — recommended for this use case
- HTML (HtmlBody) — overkill for a constituent letter
Politicians receive thousands of emails. A simple, plain-text letter feels more authentic than a branded HTML template. Keep it plain text.
Files to Create/Modify
| File | Action | Purpose |
|---|---|---|
inc/integrations/postmark-email.php |
Create | API integration + send function |
inc/post-types/pledge-signers.php |
Modify | Hook email send into form submission |
inc/politician-data.php |
Create | Shared politician lookup function |
inc/modules/page_modules/politician_email_cta.php |
Modify | Update to show "sent" confirmation |
wp-config.php |
Modify | Add API token constant |
Cost Estimate
Postmark: $15/month flat - Includes 10,000 emails - Way more than needed for 20-100/day
Mailgun alternative: ~$0.80 per 1,000 emails after free trial - 1,000 emails = $0.80 - Basically free at this volume
Security Considerations
- API token stored in
wp-config.php, not in theme files - Rate limiting — Postmark handles this, but could add WordPress-side throttle if needed
- Validation — Only send if email format is valid, zip matches, form is legitimate
- No PII logging — Don't log constituent emails in debug logs
Testing Plan
- Set up Postmark with test/sandbox mode
- Send test emails to own addresses
- Verify Reply-To works correctly
- Test with invalid zips (should gracefully skip)
- Check admin column displays correctly
- Test thank-you page messaging
Questions for Client
- Sender address:
pledges@californiaforever.com? Or different? - Email copy: Use current template or do they want to revise?
- Approval timing: Send immediately on form submit, or only after pledge is approved? - Recommend: Send immediately (more responsive constituent experience)