DraftMachine creates Gmail drafts from a CSV list + Markdown template. Drafts land in the user's Gmail Drafts folder for review before sending — nothing gets sent automatically.
bash
draftmachine --version
If the command is not found, install it:
bash
pip install draftmachine
Two files must exist:
FilePurpose~/.draftmachine/client_secret.jsonOAuth app credential downloaded from Google Cloud Console~/.draftmachine/creds.jsonCached OAuth token (created automatically by draftmachine setup)
Check for them:
bash
ls ~/.draftmachine/
client_secret.json is missing — walk the user through GCP setup#Tell the user they need to do a one-time setup to connect DraftMachine to their Gmail:
Go to Google Cloud Console and create a project (or pick an existing one).
Navigate to APIs & Services → Enable APIs & Services and enable the Gmail API.
Go to APIs & Services → Credentials → Create Credentials → OAuth client ID.
Choose Desktop app as the application type.
Click Download JSON and save the file to ~/.draftmachine/client_secret.json.
mkdir ~/.draftmachine first.Run draftmachine setup — this opens a browser window, asks for Gmail permission (draft-only scope), and saves the token.
client_secret.json exists but creds.json is missing#Run draftmachine setup to complete the OAuth consent flow.
Credentials are ready — skip to Step 3.
The CSV needs at minimum an email column (default column name: email). Any other columns become
available as template variables. Ask the user what data they have. If they paste data in the
conversation, write it to a .csv file.
Example:
csv
email,first_name,company
jane@example.com,Jane,Acme Corp
bob@example.com,Bob,
The template is a .md file with a YAML frontmatter block for the subject line and a Markdown
body using Jinja2 syntax. Ask the user what the email
should say, then write the template.
markdown
---
subject: "Quick note for {{ first_name }}"
---
Hi {{ first_name }},
{% if company %}
I came across {{ company }} and thought you might find this useful.
{% endif %}
[Body of the message here]
Best,
[Sender name]
Tips for good templates:
{{ variable }} to insert CSV column values.{% if variable %}...{% endif %} so missing values don't cause awkward blanks.{{ first_name | title }} and loops are supported.Always run --preview first. It renders the first row only to the terminal — no API calls, no
drafts created. This is a fast sanity check for template errors and formatting.
bash
draftmachine send list.csv template.md --preview
If the rendered output looks right, proceed. If there are errors (undefined variables, broken conditionals, etc.), fix the template and re-preview.
Once the preview looks good:
bash
draftmachine send list.csv template.md
If the email address is in a column other than email, use --to-column:
bash
draftmachine send list.csv template.md --to-column work_email
DraftMachine uses a two-pass strategy: it renders all rows first (aborting early if any row has template errors), then creates all drafts via the Gmail API. This means it's all-or-nothing per run — no partial draft batches on template errors.
After the command completes, tell the user:
to addresses in the terminal output).ErrorFixcommand not found: draftmachine``pip install draftmachine``No such file: client_secret.jsonComplete GCP + OAuth setup (Step 2)403 ForbiddenOAuth token lacks correct scope — re-run draftmachine setup``429 Too Many RequestsGmail API rate limit hit; DraftMachine retries 3× with backoff. If it persists, wait and re-runUndefinedError: '...' is undefinedCSV column name in template doesn't match actual column headerPartial drafts on 429No resume; re-run the full command after a short wait (may create duplicates — delete extra drafts)