# 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.

- Workflow type: agent
- Services: Gmail, urlscan.io, Slack Bot
- Categories: Operations, Engineering
- Published: 2026-08-10

## What it does

- 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 you'll need

- 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

## Prompt

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.

## How to customize

- 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

## Example output

MALICIOUS - phishing report from dana.k@acme.com

Original sender: security-alert@micros0ft-verify[.]com
Subject: Unusual sign-in activity on your account

2 links scanned, 1 skipped (internal acme.com link)

- hxxps://micros0ft-verify[.]com/login/reset
  Verdict: malicious, score 85, impersonating Microsoft
  Scan report: https://urlscan.io/result/01f4a3b2-0000-0000-0000-000000000000/

- hxxps://cdn-track[.]net/px?id=99
  Verdict: no malicious findings, score 0
  Scan report: https://urlscan.io/result/7c22e910-0000-0000-0000-000000000000/

Assessment: the sender domain is a lookalike of microsoft.com using a zero in place of the letter o, the body pressures the reader to act within 24 hours, and the first link renders a credential form styled as a Microsoft sign-in page. Recommend blocking the domain and resetting Dana's password if she entered credentials.

## FAQ

### Will the links we scan be visible to other people?

No. Every scan is submitted privately, so results are visible only to your own account. This matters more than it sounds: reported phishing emails often contain password reset links, account confirmation links, and internal document links. Scanning services default to publishing results, and real companies have leaked exactly this kind of link that way, so this workflow always sets scans to private.

### Can someone accidentally click a dangerous link in the Slack alert?

No. Every suspicious link is rewritten in a deactivated form before it reaches Slack, so it shows up as plain text rather than something clickable. Only the safe link to the scan report itself stays clickable.

### What happens if a scan has not finished when the workflow checks?

Scans take roughly ten to thirty seconds. The workflow knows a not ready response is normal rather than a failure, so it waits and checks again instead of reporting an error.

### Will the same email get triaged twice?

No. Once a verdict has been posted to Slack, the workflow labels that message as triaged, so later runs skip over it.

### Do we need a paid urlscan.io account?

You can get started on a free account. Higher scan volumes and a few of the more advanced result fields require a paid plan, so busy mailboxes will get more out of an upgrade.

### Does this replace our security analysts?

No, it removes the repetitive first pass. Clear cut cases get an immediate verdict, and anything ambiguous is explicitly flagged as needing a human look, with the evidence already gathered so the analyst starts from a full picture.

Use this prompt in General Input: https://www.generalinput.com/prompts/triage-forwarded-phishing-reports-and-post-verdicts-to-slack