Email (local MTA)
The sendmail notifier hands each message to the machine’s sendmail-compatible
program (Postfix, exim, msmtp, ssmtp), the same way crond sends MAILTO mail.
There’s no host, port, TLS, or password to set: the mail system already knows
where to send and handles queueing and retries.
Use it when the machine already sends mail. If it doesn’t, the SMTP notifier talks to Gmail, SES, or another server directly.
[notifiers.mta]type = "sendmail"Fields
Section titled “Fields”| Key | Required | What it does |
|---|---|---|
from |
yes | The From: address: "[email protected]" or "Name <[email protected]>". |
to |
yes | List of recipients, at least one. |
cc |
no | List of Cc: recipients. |
bcc |
no | List of Bcc: recipients. The mail system removes them before delivery. |
reply_to |
no | A Reply-To: address. |
sendmail_path |
no | Absolute path to a specific program. Unset: find the system one. |
template_path |
no | A Go template file that replaces the built-in plain-text message. |
To send one task’s mail to another address, use "mta:[email protected]" in
notify, much like a per-crontab MAILTO. See
One channel, several destinations.
Finding the sendmail program
Section titled “Finding the sendmail program”Without sendmail_path, RunWisp tries /usr/sbin/sendmail,
/usr/lib/sendmail, /usr/bin/sendmail, then sendmail on $PATH, in that
order. Every common mail system installs one of these.
Set sendmail_path to use a specific program:
[notifiers.mta]type = "sendmail"sendmail_path = "/usr/local/bin/msmtp"It must be an absolute path. RunWisp looks for the program at the first send, not at startup, so the config still loads on a machine where the mail package isn’t set up yet. If nothing is found, the delivery fails with an error listing the paths it tried.
RunWisp runs <program> -t -i and writes the message to its input. Addresses
are read from the headers, never passed as command-line arguments.
Retries
Section titled “Retries”Only exit code 75 (temporary failure) is retried. Any other error, like a
rejected address or a broken mail setup, fails at once, and the bell gets a
notify.delivery_failed warning with the program’s error output.
An exit code of 0 means the mail system accepted the message, not that it
was delivered. If accepted mail never arrives, look in /var/log/mail.log and
mailq.
What a message looks like
Section titled “What a message looks like”Plain text, no markup:
From: [email protected]Subject: backup-postgres failedDate: Thu, 14 May 2026 17:11:04 +0200MIME-Version: 1.0Content-Type: text/plain; charset=utf-8Auto-Submitted: auto-generatedX-Auto-Response-Suppress: AllUser-Agent: runwisp-notify/1
backup-postgres failed
Exited with code 1 after 0.3s.
Scheduled run · 14 May, 17:11.
Error: connection refuseddial tcp 127.0.0.1:5432: connect: connection refused
View run: https://runwisp.example.com/tasks/backup-postgres/01J...
--from runwisp · bright-falcon- The output block appears for failures and timeouts, up to three lines or 300 bytes.
- The View run link appears only when
external_urlis set. Auto-SubmittedandX-Auto-Response-Suppressstop out-of-office bots from replying.- Subjects with non-ASCII characters are encoded, so accents survive.
Changing the message
Section titled “Changing the message”Point template_path at your own Go template. Start from the built-in
sendmail.tmpl.txt.
It gets the whole event and the same helpers as the
Slack template. A header
value containing a line break is rejected before the message is sent.
Coming from MAILTO
Section titled “Coming from MAILTO”runwisp import cron finds MAILTO= in a crontab and prints the notifier block
to add. One difference: cron mailed whenever a job printed anything, while
RunWisp mails when a run fails. To also get mail for successful runs, add a
[[route]] with kinds = ["succeeded"]. See
Coming from cron.
What’s rejected
Section titled “What’s rejected”- A missing
from, or an emptyto. - A
from,reply_to,to,cc, orbccvalue that isn’t a valid email address. - A relative
sendmail_path.