Guide
Send Argo CD Email Notifications
Email on Argo CD sync and health changes by running nylas email send from a notifications trigger or a sidecar. No SMTP relay, no notification service mailer block, and no mailbox password in your GitOps repo.
Written by Hazik Director of Product Management
Reviewed by Qasim Muhammad
Why send Argo CD email notifications from the CLI?
Argo CD ships a notifications controller, but its built-in email service needs a full SMTP block: host, port, username, password, and from-address, all stored in the argocd-notifications-secret. The Nylas CLI removes that block entirely. It sends over the Nylas API with a single API key, so a notification trigger or a sidecar runs one command and your GitOps repo never holds a mailbox password.
Argo CD became a CNCF graduated project in December 2022 and now drives deployments across tens of thousands of clusters. Most teams want an email when an Application drifts to OutOfSync or flips to Degraded. The CLI handles those two events without a relay: install it once, key it from a Secret, and call it from whichever side of the controller you prefer.
There are two integration points. You can wire the notifications controller to a webhook service that posts to a receiver running the CLI, or you can run the tool in a sidecar that consumes the same rendered events. Both avoid the SMTP credentials the built-in mailer needs, and both keep the send logic in one command you can test locally before it ever runs in the cluster.
What is the difference between Argo CD sync and health status?
Argo CD tracks two independent states per Application. Sync status compares live cluster state against the Git desired state and reports Synced or OutOfSync. Health status reflects whether the running resources are actually working, reporting one of six values: Healthy, Progressing, Degraded, Suspended, Missing, or Unknown.
The distinction matters for which events deserve email. An OutOfSync Application means Git and the cluster disagree, which is expected during a rollout and resolves in seconds. A Degraded health status means a Deployment failed its readiness probe or a Pod is crash-looping, which usually needs a human and often persists for minutes rather than the few seconds a sync drift lasts. According to the Argo CD health documentation, the controller derives health from resource-specific rules, so a Deployment is Degraded when its progress deadline passes — the Kubernetes default progressDeadlineSeconds is 600 seconds. Route Degraded to email and let routine sync churn stay in the UI.
A useful rule of thumb: send email on a sustained Degraded status and on a sync that fails, not on every transition through Progressing or OutOfSync. A rollout passes through Progressing on every deploy, so alerting on it floods the inbox. Reserve email for the two states that mean a deploy did not converge, and keep the subject line specific to the Application and its new status so a recipient can route it without opening the UI.
How do I send email from an Argo CD notifications trigger?
The notifications controller fires a trigger when an Application changes state, then renders a template and hands it to a service. Instead of the email service, register a webhook service that posts the rendered payload to a small receiver, or run the CLI from a sidecar that watches the same events. The trigger definition lives in the argocd-notifications-cm ConfigMap.
This ConfigMap snippet defines a trigger that fires once when an Application becomes Degraded and binds it to a template. The oncePer field keys deduplication to the health status, so one crash-loop produces one email rather than one per reconciliation, which runs every 180 seconds by default. The template body carries the Application name and the new status.
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
data:
trigger.on-degraded: |
- when: app.status.health.status == 'Degraded'
oncePer: app.status.health.status
send: [app-degraded]
template.app-degraded: |
message: |
Application {{.app.metadata.name}} is now {{.app.status.health.status}}.
Sync: {{.app.status.sync.status}}How do I run the Nylas CLI as an Argo CD sidecar?
A sidecar receives the rendered notification and turns it into an email. Run a minimal container alongside your receiver that installs the CLI once at startup, then calls nylas email send per event. The grant ID is passed as the first positional argument, and --yes skips the interactive confirmation so the command works in a non-interactive Pod.
This Pod spec runs the CLI in a hardened, non-root container with the API key mounted from a Secret. The nylas email send command reads NYLAS_API_KEY from the environment and exits non-zero if the send fails, which lets the controller log a failed alert instead of swallowing it. Startup install adds about 3 seconds to the first send.
apiVersion: v1
kind: Pod
metadata:
name: argocd-email-sidecar
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
containers:
- name: nylas
image: alpine:3.20
env:
- name: NYLAS_API_KEY
valueFrom:
secretKeyRef:
name: nylas-credentials
key: api-key
- name: NYLAS_GRANT_ID
valueFrom:
secretKeyRef:
name: nylas-credentials
key: grant-id
command: ["/bin/sh", "-c"]
args:
- |
apk add --no-cache curl bash
curl -fsSL https://cli.nylas.com/install.sh | bash
nylas email send "$NYLAS_GRANT_ID" \
--to "platform-oncall@example.com" \
--subject "Argo CD: app degraded" \
--body "An Argo CD Application reported a Degraded health status." \
--yes \
--jsonHow do I avoid duplicate emails and protect the API key?
Argo CD reconciles every Application on a timer, so a single Degraded state can trigger many times before a human fixes it. Use the oncePer field in the trigger so the controller sends one email per distinct status value, not one per reconciliation. The default reconciliation interval is 180 seconds, which without deduplication produces 20 emails per hour for one stuck Application.
Store the Nylas API key in a Kubernetes Secret, never in the GitOps repo or a ConfigMap. Reference it with secretKeyRef so the value is mounted as an environment variable at runtime and stays out of your manifests. Per the Kubernetes Secret documentation, Secrets are base64-encoded at rest, not encrypted by default, so enable encryption at rest or an external secrets operator for production. Use a dedicated automation grant for sends so you can rotate or revoke it without touching a developer mailbox.
For richer alerts, send an HTML body so the Application name, status, and a link to the Argo CD UI render as formatted text in the inbox. The --body flag accepts HTML or plain text and the CLI auto-detects the format, sending HTML as text/html. This example writes the markup to a file, interpolates the live status the receiver set per event, then passes the rendered file to --body. Keep the body under five lines so an on-call engineer can triage it from a phone in under 15 seconds.
cat > alert.html <<'HTML'
<h1>Argo CD: Application degraded</h1>
<p>Application <strong>$APP_NAME</strong> is now <strong>$HEALTH</strong>.</p>
<p>Sync status: $SYNC. Open Argo CD to review and retry.</p>
HTML
envsubst < alert.html > rendered.html
nylas email send "$NYLAS_GRANT_ID" \
--to "platform-oncall@example.com" \
--subject "Argo CD: $APP_NAME is $HEALTH" \
--body "$(cat rendered.html)" \
--yes \
--jsonTrack send failures separately from deploy failures. If an Application goes Degraded and the email step also fails, you need both facts, so pass --json and write the returned message ID to the controller log. That gives an audit trail without searching inboxes by hand. Pair email with a chat channel for high-severity Applications so one delivery problem never hides a production rollback.
Next steps
- Send email from a Kubernetes CronJob -- hardened non-root container and Secret-backed key
- GitHub Actions email notifications -- failure alerts from CI workflows
- Terraform email alerts -- email on apply and drift in infrastructure pipelines
- Email to Mattermost notifications -- route alerts into team channels
- Email to Telegram notifications -- forward alerts to a mobile chat
- Command reference -- every email send flag and JSON output field
- Argo CD notifications overview -- triggers, templates, and services
- Argo CD application health -- how Degraded and Progressing are derived
- Kubernetes Secrets -- mounting the API key with secretKeyRef