> ## Documentation Index
> Fetch the complete documentation index at: https://anaconda.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Setting up notifications for deployments

export const Comments = ({children}) => {
  return <div class="my-4 px-5 py-4 overflow-hidden rounded-2xl flex gap-3 border border-zinc-500/20 bg-zinc-50/50 dark:border-zinc-500/30 dark:bg-zinc-500/10" data-callout-type="comments">
      <div class="w-4">
        <svg width="14" height="14" viewBox="0 0 640 640" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" aria-label="Comments">
            <path d="M320 112C434.9 112 528 205.1 528 320C528 434.9 434.9 528 320 528C205.1 528 112 434.9 112 320C112 205.1 205.1 112 320 112zM320 576C461.4 576 576 461.4 576 320C576 178.6 461.4 64 320 64C178.6 64 64 178.6 64 320C64 461.4 178.6 576 320 576zM280 400C266.7 400 256 410.7 256 424C256 437.3 266.7 448 280 448L360 448C373.3 448 384 437.3 384 424C384 410.7 373.3 400 360 400L352 400L352 312C352 298.7 341.3 288 328 288L280 288C266.7 288 256 298.7 256 312C256 325.3 266.7 336 280 336L304 336L304 400L280 400zM320 256C337.7 256 352 241.7 352 224C352 206.3 337.7 192 320 192C302.3 192 288 206.3 288 224C288 241.7 302.3 256 320 256z" />
        </svg>
      </div>
      <div class="text-sm prose min-w-0 w-full">
        {children}
      </div>
    </div>;
};

When you deploy a flow to run on a schedule or in response to events, you can configure the deployment to send a notification when the flow succeeds or fails, so you can stay informed about production runs without watching the UI. Anaconda Platform has built-in support for Slack and PagerDuty notifications. For email, send the notification from a step in your flow.

<Tabs>
  <Tab title="Slack">
    Slack notifications use an incoming webhook: the platform posts a message to a Slack channel of your choice when the flow succeeds or fails.

    <Steps>
      <Step title="Create an incoming webhook in Slack">
        Follow [Slack's incoming webhooks guide](https://api.slack.com/messaging/webhooks) to create a webhook for your workspace. At the end of the setup, Slack gives you a webhook URL that looks like this:

        ```text Example Slack webhook URL theme={null}
        https://hooks.slack.com/services/T0XXXXXXXXX/B0XXXXXXXXX/qZXXXXXX
        ```
      </Step>

      <Step title="Deploy the flow with notifications enabled">
        Enable notifications either for a single deploy or by default for all deploys:

        <Tabs>
          <Tab title="Per deploy">
            Deploy the flow with the `--notify-on-error` and `--notify-on-success` flags and the webhook URL:

            ```sh theme={null}
            python flow.py argo-workflows create --notify-on-error --notify-on-success --notify-slack-webhook-url <SLACK_WEBHOOK_URL>
            ```

            <Comments>
              Replace \<SLACK\_WEBHOOK\_URL> with the webhook URL from the previous step.
            </Comments>
          </Tab>

          <Tab title="By default">
            To enable notifications by default without passing the flags on every deploy, set the environment variable:

            ```sh theme={null}
            export METAFLOW_ARGO_WORKFLOWS_CREATE_NOTIFY_SLACK_WEBHOOK_URL=<SLACK_WEBHOOK_URL>
            ```

            <Comments>
              Replace \<SLACK\_WEBHOOK\_URL> with the webhook URL from the previous step.
            </Comments>
          </Tab>
        </Tabs>
      </Step>

      <Step title="Verify the notification">
        The next time the deployed flow succeeds or fails, a notification appears in the Slack channel:

        <Frame>
          <img src="https://mintcdn.com/anaconda-29683c67/VD0yQ0tXYWIdTsBU/images/platform/plat_slack_notification.png?fit=max&auto=format&n=VD0yQ0tXYWIdTsBU&q=85&s=820a198b3aec5ba576d4725a89a50a77" alt="Slack notifications showing a deployed flow run that failed and then succeeded after a retry" width="1352" height="182" data-path="images/platform/plat_slack_notification.png" />
        </Frame>
      </Step>
    </Steps>
  </Tab>

  <Tab title="PagerDuty">
    PagerDuty notifications use the Events API V2: the platform creates an event in PagerDuty when the flow succeeds or fails. You can connect the event to your on-call policies.

    <Steps>
      <Step title="Create an Events API integration in PagerDuty">
        Follow [PagerDuty's services and integrations guide](https://support.pagerduty.com/docs/services-and-integrations#create-a-generic-events-api-integration) to add an Events API V2 integration to your PagerDuty service.
      </Step>

      <Step title="Find the integration key">
        Open the service in PagerDuty and find the integration key in the Events API V2 section.
      </Step>

      <Step title="Deploy the flow with notifications enabled">
        Enable notifications either for a single deploy or by default for all deploys:

        <Tabs>
          <Tab title="Per deploy">
            Deploy the flow with the `--notify-on-error` and `--notify-on-success` flags and the integration key:

            ```sh theme={null}
            python flow.py argo-workflows create --notify-on-error --notify-on-success --notify-pager-duty-integration-key <PAGERDUTY_INTEGRATION_KEY>
            ```

            <Comments>
              Replace \<PAGERDUTY\_INTEGRATION\_KEY> with the Events API V2 integration key from the previous step.
            </Comments>
          </Tab>

          <Tab title="By default">
            To enable notifications by default without passing the flags on every deploy, set the environment variable:

            ```sh theme={null}
            export METAFLOW_ARGO_WORKFLOWS_CREATE_NOTIFY_PAGER_DUTY_INTEGRATION_KEY=<PAGERDUTY_INTEGRATION_KEY>
            ```

            <Comments>
              Replace \<PAGERDUTY\_INTEGRATION\_KEY> with the Events API V2 integration key from the previous step.
            </Comments>
          </Tab>
        </Tabs>

        After the flow runs, PagerDuty shows a new event under Incidents when the flow fails, or under Changes when it succeeds.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Email">
    To get an email alert when your flow finishes, send the email from a step in your flow. The flow formats its results as a [Metaflow card](https://docs.metaflow.org/metaflow/visualizing-results)—a quick way to visualize flow artifacts as HTML—and emails the card as an attachment. This procedure uses Postmark as the email provider, but any provider with an HTTP API works the same way; replace the `send_email` function with one that calls your provider.

    <Steps>
      <Step title="Get an API token from your email provider">
        Set up a [Postmark server](https://account.postmarkapp.com/) and set its API token as an environment variable:

        ```sh theme={null}
        export PM_SERVER_API_TOKEN=<YOUR_TOKEN>
        ```

        <Comments>
          Replace \<YOUR\_TOKEN> with the API token for your Postmark server.
        </Comments>
      </Step>

      <Step title="Add the email helper">
        Save the following as `emailer.py`. The flow calls `send_email` to send the card's HTML as an attachment:

        ```python emailer.py expandable theme={null}
        import os
        import requests
        import base64

        def send_email(from_email, to_email, subject, html):
            headers = {
                "Accept": "application/json",
                "Content-Type": "application/json",
                "X-Postmark-Server-Token": os.environ.get('PM_SERVER_API_TOKEN')
            }
            payload = {
                "From": from_email,
                "To": to_email,
                "Subject": subject,
                "HtmlBody": html,
                "Attachments": [
                    {
                        "Name": "card.html",
                        "Content": base64.b64encode(html.encode('utf-8')).decode('utf-8'),
                        "ContentType": "text/html"
                    }
                ]
            }
            response = requests.post("https://api.postmarkapp.com/email", json=payload, headers=headers)
            if response.status_code == 200:
                print("Email sent successfully!")
            else:
                print("Failed to send email:", response.json())
        ```
      </Step>

      <Step title="Run the flow">
        Save the following as `send_email_from_flow.py`. The `start` step builds a card with a chart image, and the `end` step emails the card:

        ```python send_email_from_flow.py expandable theme={null}
        import os
        from metaflow import FlowSpec, step, current, card, Flow
        from metaflow.cards import Markdown, Image, get_cards

        CAT = 'https://upload.wikimedia.org' + \
              '/wikipedia/commons/b/b9/CyprusShorthair.jpg'

        class EmailCardFlow(FlowSpec):

            @card(type='blank')
            @step
            def start(self):
                import requests
                resp = requests.get(CAT, headers = {'user-agent': 'metaflow-example'})
                current.card.append(Markdown("# Meow mail"))
                current.card.append(Image(resp.content))
                self.next(self.end)

            @step
            def end(self):
                from emailer import send_email
                send_email(
                    '<FROM_EMAIL>',
                    '<TO_EMAIL>',
                    f'Card from {current.flow_name}/{current.run_id}',
                    get_cards(
                        Flow(current.flow_name)[current.run_id]['start'].task
                    )[0].get()
                )

        if __name__ == '__main__':
            EmailCardFlow()
        ```

        <Comments>
          Replace \<FROM\_EMAIL> with the sender address configured in your email provider.<br />
          Replace \<TO\_EMAIL> with the recipient address.
        </Comments>

        Run the flow:

        ```sh theme={null}
        python send_email_from_flow.py run
        ```

        The run prints a confirmation when the email sends:

        ```text theme={null}
        Workflow starting (run-id 6752)
        [6752/start/26219 (pid 97152)] Task is starting.
        [6752/start/26219 (pid 97152)] Task finished successfully.
        [6752/end/26220 (pid 97421)] Task is starting.
        [6752/end/26220 (pid 97421)] Email sent successfully!
        [6752/end/26220 (pid 97421)] Task finished successfully.
        Done!
        ```
      </Step>

      <Step title="Verify the card content">
        To confirm the email's attachment matches the card, view the card locally:

        ```sh theme={null}
        python send_email_from_flow.py card view start
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>
