• /
  • EnglishEspañolFrançais日本語한국어Português
  • 로그인지금 시작하기

Alert RCA with Autopilot and Email

|View as Markdown (English)

This template runs Autopilot on a New Relic alert and sends the root cause analysis as a formatted HTML email. If Autopilot returns no usable response, the workflow sends an error notice instead. For shared prerequisites and configuration notes, see Autopilot RCA workflow templates.

Before using this workflow, ensure you have:

This workflow completes the following steps:

  1. Runs Autopilot with a root cause analysis prompt scoped to the alert issue ID
  2. Checks whether Autopilot returned a usable response
  3. If Autopilot succeeds, formats the response as HTML and sends it to the email destination
  4. If Autopilot fails, sends an error email with the issue ID

This workflow uses newrelic.autopilot.run and newrelic.notification.sendEmail.

name: autopilotEmailRCA
description: Automatically analyze New Relic alerts with Autopilot and send a formatted incident analysis report via email
workflowInputs:
issueId:
type: String
required: true
validations:
- errorMessage: Must be a valid New Relic issue ID in UUID format
pattern: '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$'
type: regex
emailDestinationId:
type: String
required: true
validations:
- pattern: ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$
errorMessage: "Invalid format. Please provide a valid UUID."
type: regex
steps:
- name: runAutopilot
type: action
action: newrelic.autopilot.run
version: 1
inputs:
prompt: >-
Investigate New Relic issue ${{ .workflowInputs.issueId }}.
Produce an incident analysis report covering: what triggered the alert, likely root cause, affected entities, supporting evidence, and recommended next steps.
IMPORTANT: Output your final answer DIRECTLY as clean, basic HTML. Use <h2> for section headers, <b> for bold text, <p> for paragraphs, <code> for logs/IDs, and standard <table>/<tr>/<td> tags with simple borders for tabular data. Do NOT use markdown.
selectors:
- name: agentResponse
expression: .response.finalAnswer
- name: agentResponseBlocks
expression: '(.response.finalAnswer // "") as $r | (if ($r|type)=="string" then ($r | try fromjson catch null) else $r end) as $json | if ($json|type)=="object" and ($json.card.body|type)=="array" then $json.card.body elif ($json|type)=="array" then $json elif ($json|type)=="object" and ($json.text|type)=="string" then [{"type":"Text","value":$json.text}] else [{"type":"Text","value":($r|tostring)}] end'
ignoreErrors: true
- name: checkAutopilotResponse
type: switch
switch:
- condition: ${{ (.steps.runAutopilot.outputs.agentResponse // "") != "" }}
next: sendRcaEmail
next: sendAutopilotError
- name: sendRcaEmail
type: action
action: newrelic.notification.sendEmail
version: 1
inputs:
destinationId: ${{ .workflowInputs.emailDestinationId }}
subject: Autopilot RCA Report - Issue ${{ .workflowInputs.issueId }}
message: '${{ def sanitizeHtml: gsub("(?i)<script\\b[^>]*>[\\s\\S]*?</\\s*script\\s*>"; "") | gsub("(?i)<\\s*script\\b[^>]*/?\\s*>"; "") | gsub("(?i)<style\\b[^>]*>[\\s\\S]*?</\\s*style\\s*>"; "") | gsub("(?i)<\\s*(iframe|object|embed|link|meta|form|svg)\\b[^>]*/?\\s*>"; "") | gsub("(?i)</\\s*(iframe|object|embed|form|svg)\\s*>"; "") | gsub("(?i)\\son\\w+\\s*=\\s*[^\\s>]+"; "") | gsub("(?i)javascript\\s*:"; ""); (.steps.runAutopilot.outputs.agentResponseBlocks // []) as $blocks | [ $blocks[] | if .type == "CodeBlock" then "<pre><code>" + ((.code // "") | gsub("&";"&amp;") | gsub("<";"&lt;") | gsub(">";"&gt;")) + "</code></pre>" else ((.value // "") | gsub("\\*\\*";"") | sanitizeHtml) as $clean | [ $clean / "\n" | .[] | select((. | gsub("^\\s+|\\s+$";"")) != "") ] as $lines | (reduce $lines[] as $line ([]; ($line | test("^\\s*\\|?\\s*:?-+:?\\s*(\\|\\s*:?-+:?\\s*)+\\|?\\s*$")) as $isSep | ($line | contains("|")) as $isPipe | if $isSep then . elif $isPipe then if (length > 0 and .[-1].type == "table") then .[0:-1] + [ .[-1] + {rows: (.[-1].rows + [$line])} ] else . + [ {type:"table", rows: [$line]} ] end else . + [ {type:"line", value: $line} ] end )) as $rawSegments | [ $rawSegments[] | if .type == "table" and (.rows | length) < 2 then {type:"line", value: .rows[0]} else . end ] as $segments | [ $segments[] | if .type == "table" then "<table style=\"width:100%;border-collapse:collapse;font-family:Arial,sans-serif;\">" + ([ .rows | to_entries[] | . as {key: $i, value: $row} | ($row | sub("^\\s*\\|";"") | sub("\\|\\s*$";"")) as $trimmed | [ $trimmed / "|" | .[] | gsub("^\\s+|\\s+$";"") ] as $cells | (if $i == 0 then "th" else "td" end) as $tag | (if $i == 0 then "text-align:left;padding:8px;border-bottom:2px solid #ccc;" else "padding:8px;border-bottom:1px solid #eee;" end) as $style | "<tr>" + ([ $cells[] | "<" + $tag + " style=\"" + $style + "\">" + . + "</" + $tag + ">" ] | join("")) + "</tr>" ] | join("")) + "</table>" else .value as $line | ($line | sub("^\\s+";"")) as $t | if ($t | startswith("<")) then $line elif ($line | startswith("### ")) then "<h3>" + ($line | ltrimstr("### ")) + "</h3>" elif ($line | startswith("## ")) then "<h2>" + ($line | ltrimstr("## ")) + "</h2>" elif ($line | startswith("# ")) then "<h2>" + ($line | ltrimstr("# ")) + "</h2>" elif ($line | startswith("- ")) then "<p>&#8226; " + ($line | ltrimstr("- ")) + "</p>" else "<p>" + $line + "</p>" end end ] | join("\n") end ] | join("\n") }}'
next: end
- name: sendAutopilotError
type: action
action: newrelic.notification.sendEmail
version: 1
inputs:
destinationId: ${{ .workflowInputs.emailDestinationId }}
subject: Autopilot RCA Failed - Issue ${{ .workflowInputs.issueId }}
message: >-
Autopilot could not produce findings for issue ${{ .workflowInputs.issueId }}. Please investigate manually.
next: end

How it works

The runAutopilot step uses two selectors to handle finalAnswer shape variability at the data-extraction layer:

  • agentResponse captures the raw finalAnswer value. The checkAutopilotResponse step uses this to determine whether Autopilot returned anything.
  • agentResponseBlocks normalizes the value into an array of typed block objects, handling three possible finalAnswer shapes: a plain string, a JSON-encoded object with a .card.body array, and a bare array. This gives the sendRcaEmail step a consistent structure to iterate over regardless of how Autopilot formatted its response.

sendRcaEmail processes the blocks inline:

  • CodeBlock items are rendered as <pre><code> with HTML entities escaped.
  • Other blocks pass through sanitizeHtml, which strips <script>, <style>, inline event handlers, and other potentially unsafe markup.
  • Markdown-style pipe tables are detected and converted to <table> elements with basic inline styles.
  • Heading prefixes (# , ## , ### ) and bullet markers (- ) are converted to the corresponding HTML tags.
  • All remaining lines are wrapped in <p> tags.

Unlike the Alert RCA with Autopilot and Slack template, HTML formatting is handled entirely within the sendRcaEmail step — no separate assign step is needed.

Autopilot RCA workflow templates

Shared prerequisites and configuration notes for all Autopilot RCA templates

Autopilot overview

Learn how Autopilot investigates alerts and incidents

Conditional logic

Use switch statements to branch on success or failure

Send email notifications

Full reference for the sendEmail action

Create destinations

Configure the Email destination required by this workflow

Alert RCA with Autopilot and Slack

Post RCA findings to Slack instead of email

Troubleshoot Workflow Automation

Solutions for common Autopilot and workflow integration issues

Copyright © 2026 New Relic Inc.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.