A list of five thousand subscribers usually holds a few hundred people who are ready to buy, several hundred who bought last quarter, and a long tail who have gone quiet. Each group needs a different message, yet most teams send one campaign written for the middle of the list, so recent buyers get something generic and the quiet subscribers get a hard sell they ignore.
ChatGPT can write the part of the email that should change for each subscriber, based on what that person has actually done, and Mailchimp can deliver it through a merge tag. The catch, which most guides skip, is that Mailchimp clips any text field at 255 bytes, so a whole AI-written email won't fit in one field. This walkthrough builds around that limit from the first step.
Before Step 1: a Mailchimp audience, an OpenAI API key and a spreadsheet
- A Mailchimp account with at least one audience you can export and re-import
- Access to the ChatGPT API, with an API key from platform.openai.com
- Enough comfort with CSV files to export, open and re-import one
- Google Sheets or Excel, for grouping subscribers and adding a product list per segment
Step 1: Export audience data and understand your segments
Start by exporting your Mailchimp audience data. Go to Audience, then Manage Audience, then Export. Choose the fields that matter for personalisation: first name, tags, purchase history, last open date, and product categories viewed.
Segmentation fields
The most useful fields for personalisation are tags (behaviour-based), number of purchases, average order value, last campaign open date, and any custom fields like company size or industry. You don't need engagement data from every campaign, because the last open date alone tells you whether someone is still reading.
Once you have the export, group your subscribers into rough segments. Each one gets its own prompt approach:
| Segment | Definition | Prompt goal |
|---|---|---|
| High-intent buyer | Purchased in the last 90 days | Encourage a repeat purchase |
| Warm lead | Opened the last 3 emails, no purchase yet | Build trust, offer a low-commitment entry point |
| Cold subscriber | No opens in the last 6 months | Re-engage with something free, no pressure |
Add one more column to the spreadsheet before you move on, called allowed_products. Fill it per segment with five to ten product names you actually stock and want to push. The prompt in Step 2 tells ChatGPT to choose only from that list, which is what stops it suggesting a product you don't sell.
Why Mailchimp cuts a full AI email off at 255 bytes
Mailchimp stores anything personal to one subscriber in an audience field, and you print that field in an email with a merge tag such as *|AI_OPEN|*. According to Mailchimp's own field limits, audience field values hold a maximum of 255 bytes, and the import file guidelines say longer text is clipped. A 120-word email runs to roughly 650 to 750 characters, so if you ask ChatGPT for the whole email and import it into one field, subscribers receive the first third of it and a sentence that stops halfway.
The fix is to personalise the lines that matter and write everything else once. ChatGPT writes two short fields per subscriber, and the rest of the email (header, offer, button, footer) lives in the campaign template, varied by segment with conditional merge tag blocks.
| Audience field | Who writes it | What it holds | Where it sits in the email |
|---|---|---|---|
AI_OPEN | ChatGPT, per subscriber | An opening line that refers to what they last did, under 230 characters | First paragraph |
AI_PICK | ChatGPT, per subscriber | One product suggestion from the approved list, under 230 characters | Just above the button |
SEGMENT | Your spreadsheet | high_intent, warm or cold | Never shown, it decides which conditional block each person sees |
We cap the AI fields at 230 characters because the limit is counted in bytes. Plain letters take one byte each, but curly quotes, accented letters and emoji take two to four, so a line that looks like 250 characters can still be clipped.
Step 2: Build segment-specific prompts for ChatGPT
Open ChatGPT or the API playground and write one prompt template per segment. Give the model enough about the subscriber to be specific, the product list to choose from, and a hard length limit.
High-intent buyer prompt
Write two lines for a personalised email to a subscriber who: - Purchased a [product category] 60 days ago - Has an average order value of AUD [amount] - Last opened an email 5 days ago Line 1: a warm opening that refers to their last purchase. Line 2: one product suggestion, chosen only from this list: [product A], [product B], [product C]. Each line must be under 230 characters. Do not mention prices, discounts or dates. Return the two lines and nothing else. Brand voice: expert but friendly, no hype, no exclamation marks.
Repeat this for each segment. The warm lead prompt should build trust and point to a low-commitment entry point, such as a buying guide or a starter product. The cold subscriber prompt should offer something free (a guide, a checklist, a consultation) with no pressure attached. The line about prices and discounts matters, because the model has no idea which offers are live and will otherwise promise one to fill the sentence.
Step 3: Generate personalised lines in batches
Use the ChatGPT API to run every row of your export through the matching prompt. The Python script below reads the CSV, sends each subscriber's segment fields to the API, writes the two lines into new columns, flags anything Mailchimp would clip, and saves a new file ready for import.
import csv
import json
import os
import urllib.request
api_key = os.environ["OPENAI_API_KEY"]
LIMIT = 255 # Mailchimp text fields hold 255 bytes
with open("subscribers.csv", newline="") as f:
rows = list(csv.DictReader(f))
for row in rows:
prompt = f"""Write two lines for a personalised email to a subscriber.
Tags: {row['tags']}
Last purchased: {row['last_purchase']}
Segment: {row['segment']}
Line 1: a warm opening that refers to what they last did.
Line 2: one product suggestion, chosen only from: {row['allowed_products']}.
Each line under 230 characters. Do not mention prices, discounts or dates.
Return the two lines and nothing else."""
payload = json.dumps({
"model": "gpt-4o-mini",
"messages": [{"role": "user", "content": prompt}],
"max_tokens": 200
}).encode()
req = urllib.request.Request(
"https://api.openai.com/v1/chat/completions",
data=payload,
headers={"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"}
)
with urllib.request.urlopen(req) as resp:
text = json.loads(resp.read())["choices"][0]["message"]["content"]
lines = [l.strip() for l in text.strip().split("\n") if l.strip()] + ["", ""]
row["AI_OPEN"], row["AI_PICK"] = lines[0], lines[1]
# flag anything Mailchimp would clip, so a person rewrites it before import
row["needs_review"] = any(len(v.encode("utf-8")) > LIMIT
for v in (row["AI_OPEN"], row["AI_PICK"]))
with open("subscribers_personalised.csv", "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=list(rows[0].keys()))
writer.writeheader()
writer.writerows(rows)
The script only sends tags, last purchase, segment and the product list to OpenAI. The subscriber's name and email address stay in your file, and there is no reason to put them in the prompt, since the opening line reads just as well without them and Mailchimp can add the first name with *|FNAME|*.
Cost depends on how long your prompts are. The figures below assume roughly 400 input tokens (the prompt, the product list and a short brand brief) and 100 output tokens (the two lines) per subscriber, at the rates on OpenAI's pricing page in September 2026.
| Model | Input / output per million tokens | Per subscriber | 5,000 subscribers |
|---|---|---|---|
| gpt-4o-mini | $0.15 / $0.60 | about $0.00012 | about $0.60 |
| gpt-4.1-mini | $0.40 / $1.60 | about $0.00032 | about $1.60 |
| GPT-4o | $2.50 / $10.00 | about $0.002 | about $10 |
For most lists gpt-4o-mini is enough, since two short lines don't need a large model. GPT-4o is worth the extra few dollars on a small segment of high-value customers, where one awkward sentence costs more than the API bill.
Read fifty before you send five thousand
Open subscribers_personalised.csv, sort by needs_review, and rewrite or shorten every flagged row by hand. Then read around fifty rows spread across all three segments. Fifty rows is a short read, and it catches the problems that would otherwise reach thousands of inboxes at once.
- Check that every product in
AI_PICKappears in that segment's approved list, and delete the line if it doesn't. - Look for prices, discounts or deadlines the model added despite the instruction, because nobody is running those offers.
- Cut anything that sounds too familiar, such as a line that quotes someone's exact order value back to them.
- Read the opening next to your template's first paragraph, since a line that repeats the subject line or the greeting will read twice.
If more than a handful of rows fail the same check, fix the prompt and rerun that segment. At the costs above, a rerun is cheaper than editing the rows one at a time.
Step 4: Import the lines into Mailchimp and send
In Mailchimp, create three text audience fields called AI_OPEN, AI_PICK and SEGMENT from your audience's field settings. Then import subscribers_personalised.csv, map each column to its field, and tick Update any existing contacts so the new values land on the subscribers you already have. Leave the needs_review column unmapped.
Build one regular campaign. Put *|AI_OPEN|* at the top of the body and *|AI_PICK|* just above the button, then wrap each segment's offer in a conditional block such as *|IF:SEGMENT=cold|* ... *|END:IF|*. Before scheduling, send a test to yourself using three real contacts from different segments, so you can see each version with its fields filled in.
To run this without a manual send each time, tag each segment during the import (Mailchimp's import screen lets you add a tag to every contact in the file) and start a Customer Journey when that tag is added. Rerun the script whenever a subscriber's segment changes, and the journey picks up the new lines.
One send, five thousand different openings
Before this workflow, every subscriber opened the same email written for the middle of the list, and the people it didn't fit learned to skip it. After it, the template stays the same while the opening line and the product suggestion change for each person. Recent buyers see something that goes with what they bought, warm leads get a low-commitment entry point, and quiet subscribers get a free guide with no pressure attached.
McKinsey's research on personalisation puts the typical revenue lift at 10 to 15 percent, and its explainer on personalisation says it can cut acquisition costs by as much as 50 percent. Those figures come from many companies and channels at once, so measure your own result. Send the personalised version to half of one segment and the generic version to the other half, then compare clicks and orders after a week.
For a deeper look at how email personalisation fits into a broader nurture strategy, see our guide on AI email nurture with Claude and HubSpot and the lead qualification agent that routes hot leads to the right rep.
Frequently asked questions
Will ChatGPT write emails that sound like our brand?
Yes, if you give it a brand voice brief in the prompt. Include a short paragraph describing your tone, do's and don'ts, and a sample email you have already sent and loved. The more context you give, the closer the output matches your voice.
How much does it cost to personalise emails with ChatGPT?
At OpenAI's published API rates in September 2026, gpt-4o-mini costs about $0.60 to personalise 5,000 subscribers, assuming roughly 400 input tokens and 100 output tokens each. The same run costs about $10 on GPT-4o, which is worth paying for small, high-value segments where the extra polish matters.
Can I automate this completely with n8n or Make?
Yes. An n8n workflow can listen for new Mailchimp subscribers, send their fields to ChatGPT and write the two lines back to the subscriber's audience fields. Keep the 230-character cap in the prompt, because the automated route writes to the same 255-byte fields as a CSV import.
Does personalisation at scale actually improve results?
McKinsey puts the typical revenue lift from personalisation at 10 to 15 percent, and says it can cut acquisition costs by as much as 50 percent. Test it on your own list by sending the personalised and generic versions to two halves of one segment and comparing clicks and orders.
Why is my personalised text cut off in Mailchimp?
Mailchimp text audience fields hold a maximum of 255 bytes, and anything longer is clipped on import. Accented letters and curly quotes use more than one byte each, so cap each AI-written field at about 230 characters and flag longer rows before you import.