Complete setup instructions for EmailingEssay plugin.
- Prerequisites
- Environment Variables
- Installation
- Verification
- Scheduling Reply Ingestion
- Troubleshooting
-
Create a dedicated Gmail account for AI
- Use a separate account from your personal email
-
Enable 2-Step Verification
- Go to Google Account Management → Security → 2-Step Verification
-
Generate a 16-digit App Password
- Go to Google Account Management → Security → App Passwords
- Select "Mail" → Save the generated 16-digit password
All variables are mandatory.
| Variable | Description |
|---|---|
ESSAY_APP_PASSWORD |
Gmail app password (16 digits, no spaces) |
ESSAY_SENDER_EMAIL |
Sender email address (AI's Gmail) |
ESSAY_RECIPIENT_EMAIL |
Recipient email address (your email) |
Reply ingestion (python main.py replies fetch) reads the same Gmail account over IMAP
(imap.gmail.com) with these same three variables. No additional variable is required,
and imaplib ships with Python, so no additional dependency is installed either.
- App password is retrieved from environment variable (never hardcode)
- Use app password in Gmail 2FA environments
- Keep
ESSAY_RECIPIENT_EMAILset to your own email address
# Set environment variables (User scope)
[Environment]::SetEnvironmentVariable("ESSAY_APP_PASSWORD", "your-16-digit-password", "User")
[Environment]::SetEnvironmentVariable("ESSAY_SENDER_EMAIL", "ai@gmail.com", "User")
[Environment]::SetEnvironmentVariable("ESSAY_RECIPIENT_EMAIL", "you@example.com", "User")
# Restart PowerShell to apply changesAdd to ~/.bashrc or ~/.zshrc:
export ESSAY_APP_PASSWORD="your-16-digit-password"
export ESSAY_SENDER_EMAIL="ai@gmail.com"
export ESSAY_RECIPIENT_EMAIL="you@example.com"Then apply:
source ~/.bashrc # or source ~/.zshrcpip install yagmailpip install pytest # For running testsFor full development setup, see CONTRIBUTING.md → Development Setup section.
After setting environment variables, verify your configuration:
/essay testThis sends a test email to ESSAY_RECIPIENT_EMAIL.
/essay schedule registers essay delivery only. To pull replies in without typing the
command, register python main.py replies fetch with the OS scheduler. main.py may be
invoked by absolute path from any working directory.
schtasks /create /tn "EmailingEssay replies" /tr "python C:\path\to\EmailingEssay\skills\send-email\scripts\main.py replies fetch" /sc daily /st 07:00 /f/sc and /st set the frequency and start time — daily at 07:00 here is only an
example. If the machine runs on battery, see
Scheduled Run Not Firing on Battery.
Scheduled tasks do not inherit a shell session's variables, but they do see the User-scope variables set in Installation — no extra step is needed.
# Ingest replies daily at 07:00 (time is an example)
0 7 * * * /usr/bin/python3 /path/to/EmailingEssay/skills/send-email/scripts/main.py replies fetchcron does not read ~/.bashrc or ~/.zshrc, so the export lines from
Installation never reach it. Either declare the three variables at the top
of the crontab, or keep them in a .env file — which is read from the current working
directory, so the entry has to enter that directory first:
0 7 * * * cd /path/to/dir/with/.env && /usr/bin/python3 /path/to/EmailingEssay/skills/send-email/scripts/main.py replies fetchA scheduled run's stdout is discarded, so the trace is
~/.claude/plugins/.emailingessay/emailingessay.log.
Error:
Missing environment variables: ESSAY_APP_PASSWORD, ESSAY_SENDER_EMAIL, ESSAY_RECIPIENT_EMAIL
Solution:
- Follow the Installation steps above
- Restart your terminal/PowerShell
- Verify with
echo $ESSAY_APP_PASSWORD(Linux/Mac) or$env:ESSAY_APP_PASSWORD(Windows)
Error:
SMTPAuthenticationError: Username and Password not accepted
Possible causes:
- App password is incorrect or contains spaces
- 2-Step Verification is not enabled
- App password was revoked
Solution:
- Ensure 2-Step Verification is enabled on Google Account
- Generate a new App Password
- Update
ESSAY_APP_PASSWORDenvironment variable - Restart terminal and retry
Possible causes:
- Check spam/junk folder
ESSAY_RECIPIENT_EMAILis incorrect- Gmail sending limits exceeded
Solution:
- Verify recipient email is correct
- Look for the send in the ledger (
essay_ledger.jsonl+sent/) — every send is recorded there, and each successful send also writes INFO lines to~/.claude/plugins/.emailingessay/emailingessay.log, one for the delivery and one for the ledger record - For a
waitrun,essay_wait.logalso holds the return code; a registeredschedulenever writes it, so an old timestamp there is not evidence that nothing was sent - Wait and retry (Gmail has daily sending limits)
Symptom: python main.py replies fetch fails to connect to or log in to imap.gmail.com.
Possible causes:
- IMAP is disabled on the account (Gmail → Settings → Forwarding and POP/IMAP)
- The app password was generated before IMAP was enabled, or has been revoked
ESSAY_SENDER_EMAILnames an account other than the one the essays were sent from
Solution:
- Enable IMAP in Gmail settings, then retry
- If sending (
/essay test) works and only fetching fails, the credentials are good and the account setting is the suspect — regenerate the app password and updateESSAY_APP_PASSWORD - If neither works, both directions share the same credentials, so treat it as the Authentication Error case above
Connecting is one thing; being accepted is another. A candidate has to clear four gates — it
carries a Message-ID, its In-Reply-To matches an essay in the ledger, its From is
ESSAY_RECIPIENT_EMAIL, and the receiving MTA's own Authentication-Results shows dkim and
spf both pass. Missing any of them, the reply is skipped by design, not by failure.
The last gate is the one that surprises: forwarding, a mailing list, or a provider that rewrites
the message can break DKIM or SPF on a perfectly genuine reply. Each skip writes one INFO line
naming the gate that refused it to ~/.claude/plugins/.emailingessay/emailingessay.log, so
start there rather than guessing. The line carries the Message-ID, the sender and the reason —
never the body.
Symptom: The essay is automated via Windows Task Scheduler, but the daily run fails intermittently. Task Scheduler history shows LastTaskResult = 0x800710E0 ("The operator or administrator has refused the request").
Cause: By default, Task Scheduler refuses to start a task while the machine is running on battery power.
Solution:
- Open the task in Task Scheduler → Conditions tab
- Uncheck "Start the task only if the computer is on AC power"
- (Optional) Settings tab → enable "Run task as soon as possible after a scheduled start is missed" so a slot missed on battery still fires once back on AC
EmailingEssay | GitHub