Skip to content

Send a notification

Queues an email to a set of users, roles or addresses. The op does not talk to the mail server. It writes the message and one queue entry per recipient, and a background delivery process picks them up on its next sweep, ten seconds later on a default installation. The op reports success the moment the queue entry lands, so a rejected address or an unreachable mail server never fails the rule that sent it.

while the rule runs resolve TO and CC queue the message rule carries on seconds later, on its own render the template attach the file send failed: retry, then give up quietly missing or oversized attachment: the mail still goes out without it

Fields

TO

Who receives the message. Required. The picker lists active users and roles, and offers whatever else you type as an address entry, so one field can hold a mixture of all of them.

A user entry sends to that user's registered address. A role entry expands to every user holding that role, in any project: there is no project scoping at this point, so a role that exists in twelve projects mails all twelve projects' holders. An address entry is used exactly as typed, which covers both a bare [email protected] and a ${var} placeholder.

Two things thin the list out before anything is queued. Accounts deactivated since you built the rule are dropped, including the ones a role expanded to. Repeats inside the field collapse to one. Typed addresses skip the deactivation check entirely, which is why a hardcoded address keeps working when the matching user account does not.

When that leaves nobody at all, the message is written but no queue entry is created, nothing is sent, and the op still reports success. A rule that "stopped sending mail" after someone was deactivated fails exactly this way, with nothing in the log to point at it.

An account that is active but carries no email address survives this stage and is dropped later, at delivery.

CC

Same picker, same expansion rules, optional. Recipients here get the identical message. There is no BCC field on this form.

CC on its own is enough to deliver a message if TO resolves to nobody, because the delivery step treats the two lists together. Name the same person in both fields and they still get one message, addressed to them twice.

Subject

One line of plain text. Required. ${var} placeholders are expanded from the stash before the message is queued, so Build ${job_name} finished behaves the way you expect. A placeholder that does not resolve is left in the subject as literal text, which is how ${...} ends up in someone's inbox.

Body

Rich text editor. Required. ${var} placeholders are expanded the same way as in Subject, and you can paste HTML.

What you type is not the whole email. The body is handed to the default email template configured in the email settings, which wraps it in the standard header and footer. Two consequences: the template decides the final look, and if the template setting is cleared the recipients get an empty message with the right subject. When mail arrives blank, check that setting before anything else.

A template that errors while rendering does not stop the message either. The recipients get a message whose body is an error notice with your text dumped inside it, and the rule never hears about it.

Images referenced by a relative path are embedded in the message at delivery time. Images with a full URL or inline data are left alone.

Very long bodies are trimmed to the maximum message size from the email settings, 1 MB by default, without a mark in the text to show that it happened.

Attachment path

Path to a file or a directory on the server, optional. Accepts ${var} placeholders.

${job_dir}/output/report.pdf
/tmp/foo/${version}.log
${job_dir}/artifacts

Point it at a directory and the whole directory is zipped into a single attachment.

The path is read at delivery time, not when the op runs. If the file has been cleaned up by then, or the path never existed, the message is sent without the attachment and an error is written to the log. The rule is long finished by that point and is not affected.

The grey note under the field shows the size ceiling from the email settings. The check runs on the raw bytes, and a directory is measured by adding up the files inside it before any compression, so a folder of text that would zip down to a few kilobytes is still refused on its uncompressed total. Over the ceiling and the attachment is dropped the same way: message sent, attachment gone, error logged.

Output filename

Renames the attachment as the recipient sees it. Optional, and ignored when there is no attachment.

Blank means the file keeps its own name. When the source is a directory, .zip is appended unless you already ended the name with .zip.

Delivery and failure

Queueing is the only part that happens inside your rule. Everything below happens afterwards.

Each queued recipient is turned into an address at this point. A username with an email address on its account gives that address. A username with no email address gives nothing and is removed from the message, unless address generation is switched on in the email settings, in which case the username and the configured domain are pasted together.

A send that fails is retried on later sweeps, up to a maximum attempt count from the email settings, 10 by default. When the attempts run out, the queue entry is deactivated and an "Email delivery failed" event is raised, carrying the error and the addresses. Hook a rule to that event if you need to know about broken mail. Nothing else surfaces it.

When neither list resolves to a usable address but queue entries do exist, delivery falls back to the default recipient from the email settings. With no fallback configured the send errors and enters the retry cycle, so a message addressed only to accounts without email addresses retries ten times and then raises the failure event.

The log gets one line per resolved recipient at queue time, which is the quickest way to confirm that a role expanded to the people you expected.

If you set Return Key on the op's Options tab, the variable receives a small record containing the configuration that was sent. The message identifier in it is a fixed placeholder, not a real identifier, so there is nothing there to track a message with.

The op takes no part in rollback. On a rollback pass it sends the same mail again unless you untick it in the op options, which is a common source of duplicate "job finished" messages.

Combining with other ops

Guard the op with IF var condition THEN so a failure notice only goes out when something actually failed. Sending unconditionally from the end of a rule is how teams train themselves to ignore the mail.

Build the body text first with SET VAR or LOG Message style accumulation, then reference the variable in Body. The editor is a poor place to assemble a long report.

For attachments, produce the file first with Zip Local Files or Publish local file to log and pass its path in. Inside a job, keep the file somewhere that outlives the job directory if the delivery process might run after cleanup.

To mail the people attached to a set of topics, find the topics with Get topics that match conditions and loop with FOR eval.

Examples

A build failure notice to a role, with the collected errors in the body.

TO                  Role: Release Managers
CC                  [email protected]
Subject             Build failed for ${project_name} (${job_name})
Body                <p>The build failed with:</p><pre>${build_errors}</pre>
Attachment path
Output filename

A report mailed as a renamed attachment to one user plus an address held in a variable.

TO                  User: foo_user, ${extra_recipient}
CC
Subject             Weekly report ${current_date}
Body                <p>Report attached.</p>
Attachment path     ${job_dir}/output/report.csv
Output filename     weekly-${current_date}.csv

A whole output directory, zipped on the way out.

TO                  User: foo_user
Subject             Logs for ${job_name}
Body                <p>Full logs attached.</p>
Attachment path     ${job_dir}/logs
Output filename     ${job_name}-logs.zip