Guide
Send Email from Azure Pipelines
Azure Pipelines has no built-in email-on-failure step, and wiring an SMTP relay into a job means storing a mailbox password that breaks the moment a provider tightens auth. A cleaner path: install the Nylas CLI in a job and send over the API. One command emails the right people when a stage fails, authenticated by a secret variable, with no SMTP host and no mail daemon. This guide adds email to an Azure DevOps pipeline and scopes it to the failures worth interrupting someone for.
Written by Caleb Geene Director, Site Reliability Engineering
Reviewed by Qasim Muhammad
Command references used in this guide: nylas email send, nylas auth config, and nylas auth whoami.
How do you send email from Azure Pipelines?
Send email from Azure Pipelines by adding a job that installs the Nylas CLI and runs nylas email send. The CLI installs from a shell script in a couple of seconds on a Microsoft-hosted agent, authenticates with an API key, and sends over HTTPS. The job needs no SMTP server, no port 587, and no sendmail package. One script step turns a pipeline stage into a notifier.
This sidesteps the usual Azure DevOps email pain. There is no native email-on-failure task in the YAML schema, and a custom SMTP integration means storing a mailbox password that breaks when a provider tightens authentication. The CLI sends over the API with a key you store as a secret variable, which Azure masks in logs per Microsoft's pipeline variables documentation.
# azure-pipelines.yml — a notify job
- job: notify
pool:
vmImage: ubuntu-24.04
steps:
- script: |
curl -fsSL https://cli.nylas.com/install.sh | bash
export PATH="$HOME/.config/nylas/bin:$PATH"
nylas auth config --api-key "$(NYLAS_API_KEY)"
nylas email send \
--to team@example.com \
--subject "Pipeline $(Build.BuildId) finished" \
--body "Repo $(Build.Repository.Name), branch $(Build.SourceBranchName)." \
--yes
displayName: Email pipeline resultHow do you authenticate the CLI in an Azure pipeline?
Authenticate with nylas auth config --api-key "$(NYLAS_API_KEY)", reading the key from a secret pipeline variable. This is the headless auth path with no browser and no OAuth redirect, which is what a hosted agent needs. Define the key as a secret variable on the pipeline or in a variable group, and Azure DevOps keeps it out of job logs and out of forked-PR builds.
Treat the key like any deployment secret: never hard-code it in azure-pipelines.yml, and store shared keys in a variable group linked to Azure Key Vault so rotation happens in one place. Run nylas auth whoami first if you want a sanity check before sending. The key authorizes sending from the connected account, so rotate it within minutes if it ever surfaces in a log. Secret variables are not decrypted into the environment automatically, so map them explicitly as shown below per Microsoft's variable groups documentation.
- job: notify
pool:
vmImage: ubuntu-24.04
variables:
- group: nylas-secrets # holds NYLAS_API_KEY (Key Vault backed)
steps:
- script: |
export PATH="$HOME/.config/nylas/bin:$PATH"
nylas auth config --api-key "$NYLAS_API_KEY"
nylas auth whoami
env:
NYLAS_API_KEY: $(NYLAS_API_KEY) # map the secret explicitly
displayName: Configure and verify Nylas CLIHow do you email only on pipeline failure?
Email only on failure by gating the job or step with condition: failed(), so it runs when an earlier stage fails and stays silent on green runs. That is the difference between useful alerting and inbox noise. Azure evaluates the condition with the pipeline expression language, and failed() returns true only when a dependency in the same stage failed.
Place the notify job in a late stage and set dependsOn so it sees the outcome of build and test. Enrich the message with predefined variables Azure injects — $(Build.BuildId), $(Build.SourceVersion), $(System.TeamFoundationCollectionUri) — so the recipient lands on the failing run in one click. A good failure email answers what broke and where in the subject line, with the run URL in the body. See Microsoft's conditions documentation for the full set of status functions.
- stage: notify
dependsOn:
- build
- test
condition: failed() # only when an upstream stage failed
jobs:
- job: alert
pool:
vmImage: ubuntu-24.04
steps:
- script: |
curl -fsSL https://cli.nylas.com/install.sh | bash
export PATH="$HOME/.config/nylas/bin:$PATH"
nylas auth config --api-key "$NYLAS_API_KEY"
RUN_URL="$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId)"
nylas email send \
--to oncall@example.com \
--subject "FAILED: $(Build.Repository.Name) build $(Build.BuildId)" \
--body "Branch $(Build.SourceBranchName) ($(Build.SourceVersion)). See $RUN_URL" \
--yes
env:
NYLAS_API_KEY: $(NYLAS_API_KEY)
displayName: Email on failureWhat should the failure email include?
A failure email from Azure Pipelines should be scannable in ten seconds: status, repository, branch, commit, and a direct run link near the top. Keep the body short and send HTML only when a heading and a link improve the scan. Avoid pasting full logs, which already live in the Azure DevOps run with search and retention. The --body flag accepts HTML or plain text, and the CLI auto-detects which.
Build the HTML in a heredoc and pass it to --body. This keeps the YAML readable and lets you include a heading, the failing stage, and an owner line that survives forwarding. One concrete number worth tracking: keep the recipient list under five for high-severity alerts so complaint rates stay low and the messages keep landing in inboxes rather than spam folders.
- script: |
export PATH="$HOME/.config/nylas/bin:$PATH"
cat > email.html <<'HTML'
<h1>Pipeline failed</h1>
<p>The deploy stage did not finish. Owner: platform-oncall@example.com</p>
<p>Open the Azure DevOps run for logs and a re-run button.</p>
HTML
nylas email send \
--to oncall@example.com \
--subject "Deploy failed: $(Build.Repository.Name)" \
--body "$(cat email.html)" \
--yes
env:
NYLAS_API_KEY: $(NYLAS_API_KEY)
displayName: Send HTML failure reportHow do you reuse the job for deploy approvals?
Reuse the same notify job to email a deploy-approval prompt by removing the failed() condition and running it before a manual approval gate. Azure DevOps environments support manual approval checks that pause a stage, and an email pointing the approver at that pending run shortens the wait. The send command is identical; only the subject, recipients, and trigger condition change.
Add --track-opens to confirm the approver saw the request, and --metadata key1=release-1.4.2 to tag the message so it is filterable later. A message carries up to 50 custom key=value pairs; only the five indexed keys (key1–key5) are filterable in API queries. Run the smoke test against a throwaway branch first; rotating a secret and discovering a stale key during a real release is the wrong time to learn the channel broke. See Microsoft's approvals and gates documentation for the gate setup.
- script: |
export PATH="$HOME/.config/nylas/bin:$PATH"
nylas auth config --api-key "$NYLAS_API_KEY"
RUN_URL="$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId)"
nylas email send \
--to release-manager@example.com \
--subject "Approval needed: $(Build.Repository.Name) $(Build.BuildId)" \
--body "Approve or reject the pending deploy: $RUN_URL" \
--track-opens \
--metadata key1=approval \
--yes
env:
NYLAS_API_KEY: $(NYLAS_API_KEY)
displayName: Email approval requestNext steps
- Send Email from Buildkite Pipelines — Send build failure email from a Buildkite pipeline with Nylas CLI
- Send Email from Google Cloud Build — Send build failure emails from Google Cloud Build with the CLI.
- GitHub Actions email notifications — the same pattern in Actions with
if: failure() - Send email from GitLab CI pipelines — masked variables and
when: on_failure - PowerShell email in CI/CD — Windows agents and
irm install.ps1 | iex - Email to Slack notifications — route the same alerts to a channel
- Email to Discord notifications — mirror pipeline alerts to Discord
- Full command reference — every flag and subcommand documented