This local Codex plugin uses a Node.js notifier to send an email whenever Codex finishes a task.
- Chinese README
- Chinese configuration guide
- Chinese Microsoft OAuth2 setup guide
- Chinese usage guide
- Chinese troubleshooting guide
- Codex native
notifypayloads via~/.codex/config.toml - Codex
Stophook payloads viahooks.json - SMTP delivery through
nodemailer - SMTP password auth and Outlook / Microsoft 365 OAuth2 auth
- De-duplication by
session_id + turn_id, so enabling bothnotifyandStopwill still only send one email per completed turn
.codex-plugin/plugin.json: local plugin manifestscripts/email-notify.mjs: the notifier entrypointconfig.example.json: example SMTP and recipient settingshooks.json: optionalStophook wiring
Create config.local.json in this directory or set environment variables.
Environment variables:
CODEX_EMAIL_NOTIFY_AUTH_TYPECODEX_EMAIL_NOTIFY_TOCODEX_EMAIL_NOTIFY_FROMCODEX_EMAIL_NOTIFY_SUBJECT_PREFIXCODEX_EMAIL_NOTIFY_SMTP_HOSTCODEX_EMAIL_NOTIFY_SMTP_PORTCODEX_EMAIL_NOTIFY_SMTP_SECURECODEX_EMAIL_NOTIFY_SMTP_USERCODEX_EMAIL_NOTIFY_SMTP_PASSCODEX_EMAIL_NOTIFY_OAUTH2_PROVIDERCODEX_EMAIL_NOTIFY_OAUTH2_USERCODEX_EMAIL_NOTIFY_OAUTH2_CLIENT_IDCODEX_EMAIL_NOTIFY_OAUTH2_CLIENT_SECRETCODEX_EMAIL_NOTIFY_OAUTH2_REFRESH_TOKENCODEX_EMAIL_NOTIFY_OAUTH2_ACCESS_TOKENCODEX_EMAIL_NOTIFY_OAUTH2_ACCESS_TOKEN_EXPIRESCODEX_EMAIL_NOTIFY_OAUTH2_TENANTCODEX_EMAIL_NOTIFY_OAUTH2_TOKEN_URLCODEX_EMAIL_NOTIFY_OAUTH2_SCOPECODEX_EMAIL_NOTIFY_DRY_RUNCODEX_EMAIL_NOTIFY_STATE_DIR
Example local config:
{
"to": ["you@example.com"],
"from": "codex@example.com",
"subjectPrefix": "[Codex]",
"smtp": {
"host": "smtp.example.com",
"port": 587,
"secure": false,
"user": "smtp-user@example.com",
"pass": "app-password"
}
}Outlook / Microsoft 365 OAuth2 example:
{
"to": ["you@example.com"],
"from": "your-outlook@example.com",
"subjectPrefix": "[Codex]",
"authType": "oauth2",
"smtp": {
"host": "smtp-mail.outlook.com",
"port": 587,
"secure": false,
"user": "your-outlook@example.com"
},
"oauth2": {
"provider": "microsoft",
"tenant": "common",
"user": "your-outlook@example.com",
"clientId": "your-microsoft-app-client-id",
"clientSecret": "your-microsoft-app-client-secret",
"refreshToken": "your-microsoft-refresh-token",
"scope": "https://outlook.office.com/SMTP.Send offline_access"
}
}Notes:
- Set
authTypetooauth2to force OAuth2 mode. - The script defaults to the Microsoft v2 token endpoint under
https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token. - Use
tenant = "common"as a broad default, or replace it with your tenant ID or domain. - For a beginner-friendly path, use
npm run token:microsoft -- --client-id <CLIENT_ID>to get a refresh token through Microsoft device sign-in.
You must register the notifier in your own ~/.codex/config.toml.
Add:
notify = ["node", "/absolute/path/to/codex-email-notify/scripts/email-notify.mjs"]Example for this repository layout:
notify = ["node", "/root/plugins/codex-email-notify/scripts/email-notify.mjs"]Without this notify entry, Codex will not call the plugin after a task completes.
The current workspace is configured to call:
notify = ["node", "/root/plugins/codex-email-notify/scripts/email-notify.mjs"]That makes Codex invoke the script after task completion through its native notifier pipeline.
If you also enable hooks in ~/.codex/config.toml:
[features]
codex_hooks = truethe bundled hooks.json can be used as a Stop-hook fallback. The notifier de-dupes repeated events for the same turn.
Dry-run without sending email:
echo '{"event":"agent-turn-complete","session_id":"s1","turn_id":"t1","cwd":"/root","model":"gpt-5.4","input_messages":[{"role":"user","content":"run the tests"}],"last_assistant_message":"Tests passed."}' \
| node /root/plugins/codex-email-notify/scripts/email-notify.mjs --dry-run