Skip to main content

Importing a list

Upload a file or sync from WinRed or Anedot. A list has one of four sources: A list is processing while the import runs and ready when it is done. You cannot send to a list that is not ready; the API returns 409 EMAIL_LIST_NOT_READY.

Where the uploader lives

Every file you upload to the platform now goes through one page: Assets > File Uploads. Pick Email recipients as the kind and drop the file: the file you upload is the list, named after the file unless you rename it, so there is no list to create first. Map the columns, name it, and choose who can use it: the one sending domain its contacts signed up to hear from, or the whole organization. There is no default, so a list for one committee never becomes available to another committee’s campaigns by accident. Then record consent. Texting contacts, opt-out numbers, email unsubscribes, texting media, and email images are the other kinds on the same page. A campaign combines lists by attaching several of them, exactly as a texting project attaches contact lists, so there is no reason to import two files into one list. The old Email > Lists > Import link still works and redirects to the uploader with the kind already selected, so existing bookmarks are fine.

Importing over the API

POST /v1/email/lists/import does the whole thing in one call: give it an HTTPS URL to a CSV you host, and it fetches, stages, and commits it as a new list. name defaults to the file name; email_domain_id scopes the list to one sending domain, and omitting it leaves the list available to every campaign.
consent.source is one of donation_form, petition, signup_form, event, purchased, rented, or other. It is the same attestation the wizard asks for, and the same reasons to answer honestly apply. mapping is optional. Leave it out and the platform uses the mapping it recognizes from the export’s own headers, which is what you want when the file came from a common ESP. If neither your mapping nor the recognizer finds an email column, the call returns 400 VALIDATION_ERROR and details.headers lists the headers it read, so the retry can name the right column instead of guessing. The response is 202 with an import id; the import runs in the background and its progress and row counts are shown on the list in the dashboard, and in the import summary over the API. The request takes no options: sending that field returns 400 VALIDATION_ERROR.

What import removes and holds back

Every import, from the uploader or the API, applies the same checks:
  • Malformed addresses are rejected and reported.
  • Likely typos in the domain are skipped, not corrected. A row whose domain is a known misspelling of a major mailbox provider, such as gmial.com, is counted in the import summary as “Likely typo in the domain”. Fix the address in your file and import it again.
  • Role addresses such as info@, admin@, and sales@ are always removed. They reach a shared inbox rather than a person and complain at a far higher rate than personal addresses, so there is no option to keep them.
  • Disposable addresses from throwaway-mailbox services are removed. The list we check covers several thousand such domains.
  • Yahoo-run mailboxes are removed from every list: Yahoo, AOL, AT&T, Verizon, Cox, Frontier and the other domains Yahoo hosts, detected by the domain’s mail servers so a provider that moves to Yahoo is covered. Recipients at those providers report political email as spam many times more often than anyone else, and one shared sending reputation carries every customer. The import summary counts them; the same rule applies to contacts added over the API and to donor-platform syncs. There is no option to keep them.
Everything removed before it joined the list is counted on the list itself: the lists page shows “removed at upload” with the breakdown by reason (Yahoo/AOL first), and the list’s detail page has the same figure as a tile. Over the API the list object carries it as removed_at_upload.
  • Addresses that cannot receive mail, such as a domain with no mail server, and addresses that already bounced or complained on this platform, are removed, as are duplicate rows in the same file.
  • Addresses currently held by screening are imported but held back, and the import summary reports them as screened. See Address screening at send time.
Suppressed addresses stay suppressed: re-importing a file does not bring back anyone who unsubscribed, bounced, or complained.

Donor syncs and segments

Two of the four sources are worth calling out because they are not files: WinRed and Anedot syncs build an email list from your donor records automatically, so people who give keep arriving on the list without anyone exporting a CSV. Consent comes from the donation form itself, which is the cleanest provenance an email list can have. Create one from Email > Lists > New dynamic list (or from Contact Management); one connection feeds both a text list and an email list, and the email list’s page shows the connection details and settings. The same picker offers Recent openers and Recent clickers: lists of everyone who opened or clicked a campaign in a window you choose, refreshed nightly. A refund can park a donor off the list, and a later gift brings them back; retention works the same way. These lists are managed through the connection rather than deleted, so the Delete action is not offered on them. Segments are lists built from contacts already in the platform, using rules rather than a file. Engagement rules are the useful ones: everyone who opened in the last 30 days, everyone who clicked a particular campaign, everyone who has not engaged in 90 days. Giving rules read your synced donations: total given, recurring, gave recently, number of gifts, any single gift above an amount, and the donation source (refcode, source code, UTM parameters, page name). Giving is counted net of refunds: a refunded or charged-back gift does not count toward a total or a gift count, and a gift that arrives through both a webhook and a scheduled report is counted once. A random split rule takes a stable slice of a list, so two segments with 0-50 and 50-100 never overlap; that is how you run two campaigns against halves of one list. Because a segment is defined by its rules, it reflects the current state of your contacts each time you use it rather than a snapshot from the day you built it, and it can refresh nightly. Every list requires a consent attestation when you create it: a short statement of how the people on it agreed to hear from you, plus an optional note. This is not a checkbox to click past. It is the record you will want if a complaint is ever escalated, and the honest answer determines what happens next. A list from your own donate-page opt-in behaves differently from a list you bought.

Acquired lists

If a list came from anywhere other than your own sign-up flow, set its acquired field. Doing so is in your interest, not against it: an acquired list that is not declared is far more likely to trip a deliverability breaker mid-send and pause your campaign. An acquired list is not blocked from sending. Declaring it has one consequence: warm-up runs on half steps. The daily ceiling is halved at every stage of the warm-up ramp, so a list with less certain provenance reaches mailbox providers more slowly.

List quality score

When an import finishes, the list gets a quality grade: Good, Fair or Poor. It is built from what the import measured and from our own history with the addresses: The grade is the worst of these. Lists synced from WinRed or Anedot get the same checks; they have no upload step, so they are graded on their addresses and history alone, and re-graded weekly as new donors sync in. Lists under 500 rows are not graded, and segments are not scored, since each is built from graded lists.
  • Good: sends normally.
  • Fair: sends at the slower pace used for acquired lists while the domain is warming up, and the campaign checklist shows a warning.
  • Poor: our team reviews the list before it can be sent to, usually within a business day. Campaigns using it cannot start until it is approved. If it is not approved, the list page says why.
The list page shows the grade and each signal. Sending first to people who signed up or engaged recently is the fastest way to protect a sending domain when a list scores below Good.

Address screening at send time

There is no separate cleaning step and no charge for one. Every campaign email is screened as it is sent, using the strictest setting of the mail provider’s automatic validation. An address it rates as likely undeliverable is not sent to. What happens to a screened address:
  • The message is recorded with status suppressed and reason auto_validation.
  • It is not counted as a bounce, so it does not count toward your bounce rate or the deliverability breakers, and it does not fire the email.bounced webhook.
  • The address is held out of all sends on the platform for 90 days, for every organization. After 90 days it is checked again on its next send.
  • The campaign report shows the total as Screened as invalid.
  • You are billed the normal per-recipient email rate for it, the same as a bounce, because the message was handed to the mail provider.
Screening is a safeguard, not a guarantee. It does not confirm that a mailbox exists at the large providers, so an address that has never been seen before and is dead can still bounce once. A permanent bounce from a bad address suppresses it for good; see Bounces, complaints, and suppressions. A campaign sends to every subscribed contact on its lists that is not suppressed. There is no recipient policy to choose.

Downloading a list

Download on the list page saves the file straight away, the same as a texting contact list. An uploaded list offers two files:
  • Current list: the columns from the file you uploaded, in the order they arrived, followed by email, status, and status_reason, showing each contact as it stands now. A contact the platform will no longer mail, for example an address mailbox providers reported as not existing, reads suppressed with the reason.
  • Original upload: the file exactly as you uploaded it.
A list synced from a donation platform has no uploaded file, so Download saves the current list.

Contact statuses

Only subscribed contacts are mailed. The rest are excluded automatically, and none of them can be restored by re-importing the same file.

Removing contacts

Removing an address unsubscribes it rather than deleting the row, because the row carries the bounce and complaint history that makes suppression survive your next import. To erase an address entirely, use forget this address.

Suppressions and the sunset policy

Suppressions, bounces, complaints, unsubscribes, and the 90-day hold and 180-day sunset all work the same way regardless of which list an address is on, so they have their own page: Bounces, complaints, and suppressions. The short version: an address that bounces permanently or complains is suppressed for you automatically, unsubscribes are honored immediately, and contacts who have not engaged in 90 days stop being mailed before they can damage your reputation. Opening or clicking one of your emails counts as engagement and starts that clock over.

Bulk contact upsert over the API

POST /v1/email/lists/{id}/contacts takes up to 1,000 contacts per call and returns a per-row outcome, so one bad address does not cost you the batch:
Fix and resend only the rows that came back rejected.