Deliver Reports to Slack and Email
Overview
A report can post itself to Slack and email itself to a list of recipients as soon as it
finishes running. Where it goes is recorded in the report's own report.yaml, so the schedule
that runs it does not need to know anything about channels or addresses.
Two things have to be true before anything is sent. The report needs a delivery section in its
manifest, and the run needs the --deliver flag:
uc-bq run revenue-by-payment --deliver
uc-bq run-all --deliver --no-analysis
Delivery attaches report.pdf when one exists, and falls back to chart.png when it does not.
A delivery failure is logged in the run summary but never fails the run. If Slack is unreachable or an email bounces, the report still generates and its files are still written.
Add a delivery section to a report
Add a delivery block to the report's report.yaml:
delivery:
slack:
channels: ["C0123456789"]
email:
to: ["ceo@example.com", "marketing@example.com"]
subject: "Weekly: Revenue by Payment Method"
provider: "sendgrid"
Slack and email fire independently, so a failure in one does not stop the other. The subject
field is optional and defaults to the report name. Reports with no delivery section ignore
--deliver entirely.
You can edit the manifest by hand, or let the CLI do it:
uc-bq config add-slack revenue-by-payment C0123456789
uc-bq config set-email revenue-by-payment \
--to=ceo@example.com,marketing@example.com \
--provider=sendgrid \
--subject="Weekly: Revenue by Payment Method"
uc-bq config show-delivery revenue-by-payment
All the delivery subcommands are listed in the CLI reference.
Choose when delivery happens
By default a report is delivered on every run. Set mode to alarm_only to deliver only when
an alarm fires, which turns a noisy weekly report into a quiet one that speaks up when a number
moves:
delivery:
mode: "alarm_only"
slack:
channels: ["C0123456789"]
mention_on_alarm: "@channel"
mention_on_alarm is Slack-specific and is added to the notification when a critical severity
alarm fires. Both fields have CLI equivalents:
uc-bq config set-delivery-mode revenue-by-payment alarm_only
uc-bq config set-mention-on-alarm revenue-by-payment "@channel"
Defining the alarms themselves is covered in Report alarms.
Set up Slack
Create a Slack app at api.slack.com/apps and choose Create New App, then From scratch. Name it something recognisable such as "UltraCart Reports" and pick your workspace.
Under OAuth & Permissions, add two Bot Token Scopes:
files:write, so the app can upload the report filechat:write, so the app can post the accompanying message
Select Install to Workspace, authorize the app, and copy the Bot User OAuth Token. It
begins with xoxb-. Export it where your reports run:
export SLACK_BOT_TOKEN=xoxb-your-token-here
Find the channel ID by right-clicking the channel in Slack, choosing View channel details,
and scrolling to the bottom. It looks like C0123456789.
The channels field takes channel IDs, not channel names. #weekly-reports will not work.
The bot also has to be a member of the channel. In the channel, type /invite @YourBotName
before the first delivery.
Add the channel to the report:
uc-bq config add-slack revenue-by-payment C0123456789
Set up email
Every provider uses a REST API, so there is no SMTP configuration and no extra dependency, apart from AWS SES. All of them need a sender address:
export EMAIL_FROM=reports@example.com
Then pick one provider and set its key. The variable names are listed in the Configuration reference.
SendGrid
Create an API key at Settings, then API Keys, with either Full Access or Mail Send permission.
export SENDGRID_API_KEY=SG.xxxxxxxxxx
Set provider: "sendgrid" in the manifest.
Postmark
Create a Server, open API Tokens, and copy the Server API Token.
export POSTMARK_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Set provider: "postmark". Your EMAIL_FROM address has to be verified in Postmark under
Sender Signatures first.
Mailgun
Open Sending, then Domains, select your domain, and copy the API key.
export MAILGUN_API_KEY=key-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export MAILGUN_DOMAIN=mg.example.com
Set provider: "mailgun". Free Mailgun accounts can only send to verified recipients, so add a
custom domain before relying on it.
Resend
Create a key under API Keys.
export RESEND_API_KEY=re_xxxxxxxxxx
Set provider: "resend". Verify your sending domain in the Resend dashboard first.
AWS SES
Verify your domain or sender address in the SES console and provide AWS credentials through any standard method: environment variables, a shared credentials file, or an IAM role.
export AWS_ACCESS_KEY_ID=AKIAxxxxxxxxxx
export AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxx
export AWS_REGION=us-east-1
SES is the one provider that needs an extra package:
npm install @aws-sdk/client-sesv2
Set provider: "ses". New SES accounts start in sandbox mode and can only send to verified
addresses until you request production access.
Test it
Run the report with delivery enabled and analysis switched off, so the round trip is quick:
uc-bq run revenue-by-payment --deliver --no-analysis
The run summary reports each delivery target and whether it succeeded. A failure there points at the environment variable or the channel membership rather than at the report.
Deliver several reports as one document
Sending five reports as five attachments is worse than sending one. A deck combines several
reports into a single branded PDF with a cover page and a table of contents, and carries its own
delivery section:
uc-bq deck run weekly-executive --deliver
See Decks and dashboards.
Troubleshooting
Delivery problems almost always come down to a missing environment variable or a Slack channel the bot cannot post in. The specific error messages, and what each one means, are collected in Troubleshooting.
Related Documentation
- CLI reference - the
--deliverflag and theconfigdelivery subcommands - Configuration reference - every environment variable delivery reads
- Report alarms - deliver only when something needs attention
- Scheduling and automation - supplying these variables to cron and GitHub Actions