Overview
Distribution lists allow you to create reusable groups of email addresses that can be used across multiple elections. This simplifies bulk email management and ensures consistency when inviting the same groups of voters.
Use Cases
- Board Members: Create a list of all board members
- Committee Members: Group committee participants
- Residents: Maintain lists of residents by building/floor
- Stakeholders: Group stakeholders for specific elections
Creating Distribution Lists
Via Admin UI
- Navigate to Admin → Distribution Lists
- Click “Create New List”
- Enter:
- Name: Descriptive name (e.g., “Board Members”)
- Description: Optional description
- Click “Create”
Via API
Endpoint: POST /admin/distribution-lists
Request:
{
"name": "Board Members",
"description": "All current board members"
}Response:
{
"success": true,
"list": {
"id": "list_abc123",
"name": "Board Members",
"description": "All current board members",
"created_at": 1704067200000,
"updated_at": 1704067200000
}
}Managing Emails
Adding Emails
Via Admin UI:
- Go to distribution list details page
- Enter email addresses (one per line or comma-separated)
- Click “Add Emails”
Via API:
Endpoint: POST /admin/distribution-lists/:id/emails
Request:
{
"emails": [
"voter1@example.com",
"voter2@example.com",
"voter3@example.com"
]
}Response:
{
"success": true,
"added": 3,
"emails": [
{ "id": "email_1", "email": "voter1@example.com", "created_at": 1704067200000 },
{ "id": "email_2", "email": "voter2@example.com", "created_at": 1704067200000 },
{ "id": "email_3", "email": "voter3@example.com", "created_at": 1704067200000 }
]
}Note: Duplicate emails in the same list are automatically prevented.
Removing Emails
Via Admin UI:
- Go to distribution list details page
- Click “Remove” next to the email
Via API:
Endpoint: DELETE /admin/distribution-lists/:id/emails/:emailId
Response:
{
"success": true
}Using Distribution Lists in Elections
Via Admin UI
When sending invites:
- Go to election management page
- Scroll to “Send Invites” section
- Under “Distribution Lists”, select one or more lists
- Optionally add individual emails
- Click “Send Invites”
Via API
Endpoint: POST /admin/elections/:id/invite
Request:
{
"distribution_list_ids": ["list_abc123", "list_def456"],
"emails": ["additional@example.com"],
"invite_mode": "batch"
}Behavior:
- All emails from selected lists are included
- Individual emails are added
- Duplicates are automatically removed (case-insensitive)
- Works with both individual and batch invite modes
Database Schema
distribution_lists Table
CREATE TABLE distribution_lists (
id TEXT PRIMARY KEY, -- UUID
name TEXT NOT NULL,
description TEXT,
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
updated_at INTEGER NOT NULL DEFAULT (unixepoch())
);distribution_list_emails Table
CREATE TABLE distribution_list_emails (
id TEXT PRIMARY KEY, -- UUID
list_id TEXT NOT NULL,
email TEXT NOT NULL,
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
FOREIGN KEY (list_id) REFERENCES distribution_lists(id) ON DELETE CASCADE,
UNIQUE(list_id, email) -- Prevent duplicates
);Indexes:
idx_distribution_list_emails_list: Onlist_id(for fast lookups)idx_distribution_list_emails_email: Onemail(for reverse lookups)
Email Deduplication
Automatic Deduplication
When using distribution lists with individual emails:
- All emails are collected (from lists + individual)
- Converted to lowercase
- Duplicates removed (case-insensitive)
- Final list sent
Example:
- List A:
["user@example.com", "admin@example.com"] - List B:
["user@example.com", "voter@example.com"] - Individual:
["admin@example.com"]
Result: ["user@example.com", "admin@example.com", "voter@example.com"]
Within Lists
Duplicate emails within the same list are prevented by the UNIQUE(list_id, email) constraint.
List Management
Viewing Lists
Via Admin UI:
- All Lists: Admin → Distribution Lists
- List Details: Click on a list name
Via API:
Endpoint: GET /admin/distribution-lists
Response:
{
"lists": [
{
"id": "list_abc123",
"name": "Board Members",
"description": "All current board members",
"created_at": 1704067200000,
"updated_at": 1704067200000,
"email_count": 5
}
]
}Updating Lists
Via Admin UI:
- Go to distribution list details
- Click “Edit”
- Update name/description
- Click “Save”
Via API:
Endpoint: PUT /admin/distribution-lists/:id
Request:
{
"name": "Updated Name",
"description": "Updated description"
}Deleting Lists
Via Admin UI:
- Go to distribution list details
- Click “Delete”
- Confirm deletion
Via API:
Endpoint: DELETE /admin/distribution-lists/:id
Response:
{
"success": true
}Note: Deleting a list also deletes all associated emails (CASCADE).
Best Practices
Organization
- Use Descriptive Names: “Board Members 2024” vs “List 1”
- Add Descriptions: Explain the purpose of each list
- Keep Updated: Remove inactive members regularly
- Group Logically: Organize by role, building, committee, etc.
Maintenance
- Regular Review: Periodically review and update lists
- Remove Inactive: Remove members who are no longer active
- Verify Emails: Ensure email addresses are correct
- Document Changes: Keep track of when lists are updated
Usage
- Combine Lists: Use multiple lists for complex groups
- Add Individuals: Combine lists with individual emails
- Test First: Send test invites before bulk sending
- Monitor Results: Check invite status after sending
Limitations
Current Limitations
- No Nested Lists: Cannot create lists of lists
- No Import/Export: Must add emails manually or via API
- No Email Validation: System doesn’t validate email format (relies on email service)
- No Groups/Roles: Simple email lists only
Future Enhancements
Potential improvements:
- CSV import/export
- Nested lists (lists of lists)
- Email validation
- Member roles/permissions
- Bulk operations
API Reference
List Operations
GET /admin/distribution-lists- List all listsGET /admin/distribution-lists/:id- Get list detailsPOST /admin/distribution-lists- Create listPUT /admin/distribution-lists/:id- Update listDELETE /admin/distribution-lists/:id- Delete list
Email Operations
GET /admin/distribution-lists/:id/emails- List emails in listPOST /admin/distribution-lists/:id/emails- Add emailsDELETE /admin/distribution-lists/:id/emails/:emailId- Remove email
Election Integration
POST /admin/elections/:id/invite- Use lists in invites (viadistribution_list_ids)
Troubleshooting
Emails Not Included
Possible causes:
- List not selected in invite form
- Emails removed from list
- Duplicate emails filtered out
Solutions:
- Verify list is selected
- Check list contents
- Review deduplication logic
Duplicate Emails
Scenario: Same email in multiple lists
Behavior: System automatically deduplicates, so each email receives one invite.
Solution: This is expected behavior. If you need separate invites, use individual email mode.
See Also
- magic-link-invites - Batch invite system
- email-system - Email sending
- api-reference - Complete API documentation