Triage forwarded phishing reports and post verdicts to Slack
Every 20 minutes, suspicious emails your staff forward get their links safely scanned and a clear verdict posted to your security channel.
I want to triage the suspicious emails my staff forward to our phishing report mailbox, so my security team stops doing it by hand. Use a cron trigger that runs every 20 minutes during business hours, Monday to Friday between 8am and 6pm in our local timezone.
Start with Gmail List Messages to pull unread messages carrying our "Phishing Reports" label, which is the label applied to everything sent to our phishing@ alias. For each message returned, call Gmail Get a Message using the full format so you can read the complete body along with the headers, including the From address, Reply-To, Return-Path, and Subject. Note who forwarded the report as well as the original sender inside it.
Extract every URL you find in the message body and headers. Before scanning anything, skip URLs that point at our own corporate domains, and skip links from common safe senders and routine infrastructure such as unsubscribe and tracking links belonging to vendors we already trust. This saves scan quota and avoids handing internal links to a third party. Keep track of what you skipped and why, so it can be mentioned in the summary.
Send each remaining URL to urlscan Submit URL Scan, and always set visibility to private. This is not optional. Publicly submitted URLs can be seen by anyone browsing urlscan, and reported phishing emails routinely contain password reset links, account confirmation links, and internal document URLs with tokens embedded in them. Real organisations have leaked exactly this kind of link by letting an automated playbook submit scans publicly. If visibility is omitted, the account default applies and that default may be public, so set it explicitly on every single submission.
Scanning is asynchronous and takes roughly 10 to 30 seconds. After submitting, wait, then call urlscan Get Scan Result with the UUID that the submission returned. A 404 response means the scan is not ready yet, not that it failed, so wait a few seconds and retry, up to about a minute per URL before giving up on that one and saying so in the output. From the finished result, read the overall verdict, the malicious score, and the detected brand impersonation target when the result includes one.
Do not simply forward a raw score. Weigh the urlscan verdict alongside the sender address and how it relates to any brand being impersonated, the tone and content of the email body, and whether links had to be skipped. A clean score on a URL sent from a lookalike domain impersonating our bank still deserves a human look, and a scary looking score on a well known marketing tracker usually does not.
Post one consolidated message per reported email to our security channel using the Slack Bot integration's Send a Message action, so alerts are attributed to the automation rather than to a person. Do not post a separate message per URL. Each message should say clearly whether the report looks malicious, benign, or needs a human look, and should include who reported it, the original sender, the subject, each scanned URL with its verdict and malicious score, the brand being impersonated if one was detected, a count of any skipped links, and the urlscan result link for each scan. Close with a short plain English assessment explaining the call.
Defang every suspicious URL in the Slack output so nobody clicks one by accident. Write hxxp in place of http and wrap the dots in square brackets, so that example.com becomes example[.]com. Apply the same treatment to any domains that appear in the sender address or subject line. The urlscan result links themselves are safe and should be left clickable.
Finish each report with Gmail Modify Message Labels on that message to mark it triaged, removing the UNREAD label and adding a "Triaged" label, so the next run does not process it a second time. Only mark a message triaged after its Slack message has actually been posted, so nothing is silently swallowed if a step fails.
Example output
What does this prompt do?
- Checks your phishing report mailbox every 20 minutes during business hours for emails staff have forwarded in
- Reads each report in full, pulls out every link, and scans them privately in a safe sandbox so internal links are never exposed to strangers
- Weighs the scan findings against who sent the email and what it actually says, then posts one clear verdict per report: malicious, benign, or needs a human look
- Writes links in a deactivated form so nobody on the team can click a dangerous one by accident
- Marks each report as handled so the same email is never triaged twice
What do I need to use this?
- A Gmail account for the mailbox your phishing reports land in, with a label applied to those reports (for example "Phishing Reports")
- Permission for the workflow to read that mailbox and update labels on it
- A urlscan.io account and its API key
- A Slack workspace and the security channel where verdicts should be posted
- Optional but recommended: a list of your own company domains and trusted senders whose links should be skipped
How can I customize it?
- Change the schedule: run every 20 minutes during business hours, or switch to hourly, or around the clock if your team works nights
- Adjust the skip list of company domains and trusted senders to control how much of your scan quota gets used
- Reword the verdict categories or change where they go, for example routing anything malicious to a separate high priority channel
- Change which label marks a report as handled, or have the workflow archive the message instead
FAQs
Will the links we scan be visible to other people?
Can someone accidentally click a dangerous link in the Slack alert?
What happens if a scan has not finished when the workflow checks?
Will the same email get triaged twice?
Do we need a paid urlscan.io account?
Does this replace our security analysts?
Related templates
When someone leaves, we check which shared passwords they used in their final months and post a ranked rotation list to your security channel.
Every 15 minutes, forwarded phishing reports get traced back to the server that really sent them, with a verdict in Slack and the worst senders reported.
Every Monday, check every S3 bucket for public exposure, missing encryption and weak backup settings, then get the risks ranked in Slack.
Twice every weekday, the conversations from your social inbox land on the right HubSpot contact timelines, with a Slack recap for sales.
Every morning, find the addresses that hard bounced or filed a spam complaint, update the matching HubSpot contacts, and post a short Slack recap.
Every weekday at 4pm, spot the threads that went quiet, stage a ready-to-send nudge in your mailbox, and get a ranked Slack recap.
Stop hand-checking every reported phishing email.
Let your security channel receive a finished verdict on every staff report, with the links already scanned and made safe to read.