-
Notifications
You must be signed in to change notification settings - Fork 1
Email Notifications
SMTP-based operational alerts. Default is disabled
(email.enabled: false). View / test at /settings/email.
| Event | Subject | Body |
|---|---|---|
| Build SUCCESS | Build SUCCESS — <projectId>/<buildId> |
Project + build id + link |
| Build FAILED | Build FAILED — <projectId>/<buildId> |
Same + error message (first 2 000 chars) |
| Claude usage warning | Claude usage warning: N% remaining |
Quota + reset time |
| Disk usage warning | Disk usage warning: N% used |
Used % + free GB |
Build CANCELED is not notified — the user just clicked cancel, they don't need a mail telling them so.
ClaudeUsageMonitor polls claude /status every 5 min (configurable in
server.yml under claude.usage.pollIntervalMinutes). The notifier
fires on transition past two thresholds:
-
claude.usage.warnThresholdPercent(default 80) -
claude.usage.criticalThresholdPercent(default 95)
Once active for a level, no further mails until the value drops back below — then a fresh crossing fires again. 10-minute cooldown prevents flapping.
DiskMonitor polls Files.getFileStore(workspace.root) every 10 min.
Fires on transition past email.diskUsageWarnPercent (default 85). Same
"transition only + cooldown" pattern. 30-minute cooldown.
The same threshold is reused by the webhook notifier — see Webhook Notifications and Disk Monitor.
Two paths, env recommended (keeps the password out of any tracked file):
VIBECODER_SMTP_ENABLED=true
VIBECODER_SMTP_HOST=smtp.gmail.com
VIBECODER_SMTP_PORT=587
VIBECODER_SMTP_TLS=true
VIBECODER_SMTP_USER=alerts@example.com
VIBECODER_SMTP_PASSWORD=app-specific-password # Gmail: app password, not the login one
VIBECODER_SMTP_FROM=vibe-coder <alerts@example.com>
VIBECODER_SMTP_TO=ops@example.com,me@personal.comemail:
enabled: true
host: smtp.gmail.com
port: 587
tls: true
user: alerts@example.com
passwordFile: /run/secrets/smtp_password # Docker secret — preferred over inline password
from: "vibe-coder <alerts@example.com>"
to: ops@example.com,me@personal.com
claudeUsageWarnPercent: 20
diskUsageWarnPercent: 85passwordFile is read at boot; the file isn't watched, so a password
rotation requires a restart.
| Provider | Host | Port | Notes |
|---|---|---|---|
| Gmail | smtp.gmail.com |
587 | App password required (the normal account password no longer works) |
| Outlook / Office 365 | smtp.office365.com |
587 | App password if 2FA enabled |
| AWS SES | email-smtp.<region>.amazonaws.com |
587 | Get SMTP credentials via SES console |
| Mailgun / SendGrid | provider host | 587 | API key acts as the SMTP password |
| Self-hosted Postfix | LAN host | 25 (no TLS) or 587 | Set tls: false for plain 25 |
/settings/email has a single "Test mail send" button (only enabled when
email.enabled = true). It calls EmailNotifier.sendNow synchronously and
shows the success/failure result inline. Use this after any configuration
change rather than waiting for a real build to fail.
- Engine: Jakarta Mail 2.1.3 API + Angus Mail 2.0.3 implementation.
- Async by default —
EmailNotifier.send(subject, body)returns immediately and the actual SMTP socket is opened on a background dispatcher. Build routes never block on the mail server being slow. -
sendNowis the synchronous version used by the test button. - Failures (auth, DNS, timeout) are logged to stderr with the exception message. Audit log does not record mail failures (out of scope).
-
VIBECODER_SMTP_PASSWORDlives only in.env(chmod 0600) or a Docker secret — not inserver.yml. -
tls: truefor any non-localhost provider. -
frommatches the authenticated SMTP user (DMARC / SPF). -
toincludes at least one email you actually check. - Test mail succeeds after restart.
Set email.enabled: false (or unset VIBECODER_SMTP_ENABLED). All
EmailNotifier calls become no-ops. No restart required for disable, since
the config is read fresh per send — but env vars only take effect on restart.