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 validate or 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. Name it, choose whether it is available to every campaign or only to one sending domain, then map the columns and 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. Role
addresses such as info@ and sales@ are skipped
unless you send options.allow_role, because they complain at a far higher
rate than personal addresses.
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). 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.Consent attestation
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 itsacquired 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.
Declaring a list acquired has three consequences:
- Paid validation is required before the first send. Undeclared acquired lists are where bounce rates come from.
- Warm-up runs on half steps. The daily ceiling is halved at every stage of the warm-up ramp.
- Validation goes stale after 90 days, and the sender scorecard flags it.
Paid validation
Validation checks each address before you spend a send on it. It costs $0.02 per address, and you are only charged when you run it. A 100,000-address list finishes in tens of minutes, not hours. Sending to a list you have not cleaned is how a campaign trips a bounce breaker on its first run. Validation is the cheap way to find that out before the mailbox providers do: at $0.02 an address it costs less to check a questionable list than to damage a domain’s reputation sending to it.What the verdicts mean
Every address comes back in one of four states:
Each verdict carries a reason code:
accept_all domains are now actually probed rather than assumed deliverable,
so a catch-all address lands in risky with reason accept_all instead of
showing as deliverable.
A cautious sender excludes risky addresses. A sender with a genuinely
well-collected list may keep accept-all and drop the rest. Disposable
addresses are worth dropping in every case.
What a run charges
A run is billed for every address it checks, at the per-address price, before the check starts; the count you are quoted is the count you pay for. A duplicate address within the same list is only ever charged once. An address that comes back unknown is charged like any other, is not held as an answer, and is checked again the next time you run validation. If a run stops before it delivers its verdicts, the addresses it did not reach are refunded. Verdicts go stale after 90 days. An acquired list validated four months ago is treated as unvalidated, and the sender scorecard flags it. Your own delivery data feeds the results. A hard bounce on any campaign marks the address undeliverable (platform_bounce) for the next 90 days, and a
successful delivery keeps an existing deliverable verdict current, so a
re-validation after a send reflects what your own sending already learned.
Large runs
A run on a large list proceeds in chunks rather than all at once, so progress is never lost to a single failure. The status tells you where it is:
A run paused for balance is not a lost run. Everything already validated
stays validated and stays paid for; topping up resumes it from that point rather
than starting over.
Start a run from the list page. Progress is shown on the list while it runs,
and only one run per list goes at a time. Validation is a paid, dashboard-driven
workflow, so it is not part of the public API.
Addresses that fail validation are marked
invalid and are not sent to.
Exporting the results
Once a run completes, Export results on the list page downloads a CSV of what validation found: the columns from the file you uploaded, in the order they arrived, followed by the address, its list status, and every verdict field behind it (state, reason, a 0-100 quality score, syntax, DNS, mailbox, role, disposable, free, accept-all, did-you-mean, MX record, SMTP provider, platform bounce count, and when it was validated). The filter next to the button picks what the file contains:
The three presets describe verdicts, so an address that was never validated is
outside all of them; “every contact” is the one filter that includes it.
The
score column is a 0-100 quality signal and sits right after the reason
column; it is blank for verdicts we derive from your own sending history
(platform_bounce and deliverable addresses refreshed by a delivery), since
those are certainties rather than scored estimates. mx_record,
smtp_provider, and did_you_mean are populated whenever the check reached
that stage.
Verdict columns are blank rather than false when an address has no cached
verdict. That happens when the address was never validated, or when its verdict
aged past the 90-day window. Blank means “no answer”, which is not the same as
“no”.
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.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:
rejected.