This workflow corresponds to n8n.io template #3353 — we link there as the canonical source.
This workflow follows the OpenAI → Slack recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "30gz7QjTektkBI2I",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "365 Service Alerts: Summarize and push alert to Slack",
"tags": [],
"nodes": [
{
"id": "48e59db6-a492-45bf-8865-0ec258cdd638",
"name": "Check for 365 Service Alert",
"type": "n8n-nodes-base.microsoftOutlookTrigger",
"position": [
720,
0
],
"parameters": {
"output": "raw",
"filters": {
"sender": "user@example.com"
},
"options": {},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
}
},
"credentials": {},
"typeVersion": 1
},
{
"id": "6c392e16-8bae-4336-a7ba-1c2bc39a48ec",
"name": "Post outage to Slack",
"type": "n8n-nodes-base.slack",
"position": [
1740,
0
],
"parameters": {
"text": "={{ $json.blocks[0].text.text }}",
"select": "channel",
"blocksUi": "={{ $json }}",
"channelId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultName": ""
},
"messageType": "block",
"otherOptions": {
"mrkdwn": true,
"includeLinkToWorkflow": false
}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.3
},
{
"id": "45e2f8bc-48e8-489a-9a5e-bdbbbb399bf7",
"name": "Clear email alert from mailbox",
"type": "n8n-nodes-base.microsoftOutlook",
"position": [
1940,
0
],
"parameters": {
"messageId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Check for 365 Service Alert').item.json.id }}"
},
"operation": "delete"
},
"credentials": {},
"typeVersion": 2
},
{
"id": "9a9c12d7-e43d-4db8-b764-16112d7ec61e",
"name": "Summarize service alert",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
1180,
0
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "GPT-4O-MINI"
},
"options": {},
"messages": {
"values": [
{
"role": "system",
"content": "You are a summarization assistant that rewrites Microsoft 365 Service Health alerts into Slack Block Kit-compatible messages for business and IT stakeholders.\n\nYour output must follow these rules:\n- Provide the alert summary as a **single string**, written in Slack mrkdwn format.\n- Begin with an appropriate emoji to reflect status:\n - \ud83d\udfe1 for *Investigating*\n - \ud83d\udee0\ufe0f for *Fix in Progress*\n - \u2705 for *Service Restored*\n - \u274c for *Outage*\n- Include the **service name**, a **short issue summary**, and whether **users may have been affected**.\n- Assume the organization has users primarily in the U.S. and Australia. If those regions are affected, state: \"_Your users may have been affected._\" Otherwise, add: \"_No impact expected for your user base._\". Dont specify the impact to users if this a Resolved or Service Restored alert.\n- The summary must be concise (2\u20133 short lines), clear, and neutral in tone.\n\nAdditionally, return the incident ID (e.g., `EX394347`) and the full incident link separately. These are used to create a button.\n\nYour final output must be a JSON object with these three fields:\n- `summaryText`: the markdown summary text for Slack\n- `incidentId`: the incident ID (e.g., EX394347)\n- `incidentLink`: the incident URL"
},
{
"content": "=Summarize the following Microsoft 365 alert for Slack.\n<alert>{{ $json.extractedText }}</alert>\n<hyperlink>{{ $json.incidentLink }}</hyperlink>"
}
]
},
"jsonOutput": true
},
"credentials": {},
"typeVersion": 1.8
},
{
"id": "de4751e5-e6c2-44a8-aee5-4d6fb8f09fab",
"name": "Generate Slack Block",
"type": "n8n-nodes-base.code",
"position": [
1540,
0
],
"parameters": {
"jsCode": "return [{\n json: {\n blocks: [\n {\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: $json.message.content.summaryText\n },\n accessory: {\n type: \"button\",\n text: {\n type: \"plain_text\",\n text: `View ${$input.first().json.message.content.incidentId}`,\n emoji: true\n },\n value: $json.message.content.incidentId,\n url: $json.message.content.incidentLink,\n action_id: \"button-action\"\n }\n }\n ]\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "9dd39e09-c467-4eba-ad65-43328cd69aab",
"name": "Extract M365 Incident text & link",
"type": "n8n-nodes-base.code",
"position": [
940,
0
],
"parameters": {
"jsCode": "// This function runs in N8N's Code node\nconst cheerio = require(\"cheerio\");\n\n// Get the HTML content from the previous node\nconst htmlContent = items[0].json.body.content;\n\nif (!htmlContent) {\n throw new Error(\"No HTML content found in the input\");\n}\n\n// Load HTML into cheerio (similar to jQuery for Node.js)\nconst $ = cheerio.load(htmlContent);\n\n// Extract the incident link from the anchor tag containing the incident ID\nconst incidentAnchor = $('a[href*=\"servicehealth?message=\"]').first();\nconst incidentLink = incidentAnchor.attr('href') || null;\n\n// Remove unnecessary elements if needed\n$('script, style, head, nav, footer, iframe, img').remove();\n\n// Extract the text content, preserving basic structure\nlet plainText = '';\n\n// Get the main content (customize selectors based on MS365 alert structure)\nconst mainContent = $('body') || $('main') || $('div.main-content');\n\n// Process text with basic formatting\nmainContent.find('h1, h2, h3, h4, h5, p, li, table, div').each((i, el) => {\n const tag = $(el).prop('tagName').toLowerCase();\n const text = $(el).text().trim();\n \n if (!text) return;\n \n // Add appropriate spacing and formatting\n if (tag.startsWith('h')) {\n plainText += `\\n\\n${text}\\n\\n`;\n } else if (tag === 'p') {\n plainText += `\\n${text}\\n`;\n } else if (tag === 'li') {\n plainText += `\\n- ${text}`;\n } else {\n plainText += `\\n${text}`;\n }\n});\n\n// Clean up extra whitespace and normalize line breaks\nplainText = plainText.replace(/\\s+\\n/g, '\\n').replace(/\\n{3,}/g, '\\n\\n').trim();\n\n// Set the output\nreturn [{\n json: {\n extractedText: plainText,\n incidentLink: incidentLink\n }\n}];"
},
"typeVersion": 2
}
],
"active": true,
"settings": {
"callerPolicy": "workflowsFromSameOwner",
"executionOrder": "v1",
"saveExecutionProgress": true
},
"versionId": "d773a7c3-e50b-45a4-8db0-0186847510f1",
"connections": {
"Slack": {
"main": [
[
{
"node": "Microsoft Outlook",
"type": "main",
"index": 0
}
]
]
},
"Generate Slack Block": {
"main": [
[
{
"node": "Slack",
"type": "main",
"index": 0
}
]
]
},
"Summarize service alert": {
"main": [
[
{
"node": "Generate Slack Block",
"type": "main",
"index": 0
}
]
]
},
"Check for 365 Service Alert": {
"main": [
[
{
"node": "Extract M365 Incident text & link",
"type": "main",
"index": 0
}
]
]
},
"Extract M365 Incident text & link": {
"main": [
[
{
"node": "Summarize service alert",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
slackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Built this for a dedicated Slack outage-notifications channel — works well on both desktop and mobile.
Source: https://n8n.io/workflows/3353/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Marketing agencies, digital agencies, and freelancers who need to streamline their client onboarding process and create consistent, professional documentation for new clients. Perfect for teams handli
💡 How It Works
> Transform Your Email Workflow with Intelligent Automation
Clone_Viral_TikToks_with_AI_Avatars___Auto_Post_to_9_Platforms_using_Perplexity___Blotato. Uses httpRequest, telegramTrigger, openAi, googleSheets. Event-driven trigger; 42 nodes.
1-Clone_Viral_TikToks_with_AI_Avatars___Auto_Post_to_9_Platforms_using_Perplexity___Blotato. Uses httpRequest, telegramTrigger, openAi, googleSheets. Event-driven trigger; 42 nodes.