Posts to Slack when new mail links to a site outside your expected list, with how recently that site was registered and who runs it.
Uses
Gmail
IPWHOIS.io
RDAP
Slack
Flag emails that link to unfamiliar websites
mailSearch to blank.Set mailSearch to blank.slackChannelId to blank.Set slackChannelId to blank.expectedDomains to blank.Set expectedDomains to blank.checkedLabel to Links checked.Set checkedLabel to Links checked.maxMessagesPerRun to 10.Set maxMessagesPerRun to 10.maxHostsPerMessage to 10.Set maxHostsPerMessage to 10.mailSearch, -label:, @checkedLabel, ] with nothing and save it as linkQuery.Join a list of [mailSearch, -label:, @checkedLabel, ] with nothing and save it as linkQuery.messageLimit to maxMessagesPerRun multiplied by 1.Set messageLimit to maxMessagesPerRun multiplied by 1.hostLimit to maxHostsPerMessage multiplied by 1.Set hostLimit to maxHostsPerMessage multiplied by 1.expectedDomains with "Split expectedDomains with
replaced by , with replaced by in lowercase by , and save it as expectedList.linkQuery. Save it as arrived.List emails matching linkQuery. Save it as arrived.readCount to 0.Set readCount to 0.postCount to 0.Set postCount to 0.message in arrived.emails:For each message in arrived.emails:readCount is greater than or equal to messageLimitIf readCount is greater than or equal to messageLimitYes
No
No steps
readErrorIf a step below fails, save the error as readErrorTry
message.id and save it as messageId.Trim message.id and save it as messageId.messageId is emptyIf messageId is emptyYes
No
No steps
message.from and save it as fromHeader.Trim message.from and save it as fromHeader.addressPart to fromHeader.Set addressPart to fromHeader.fromHeader contains <If fromHeader contains <Yes
fromHeader split by < split by > and save it as addressPart.Get the first item of the last item of fromHeader split by < split by > and save it as addressPart.No
No steps
addressPart split by @ lowercase and save it as senderDomain.Make the last item of addressPart split by @ lowercase and save it as senderDomain.subject to (no subject).Set subject to (no subject).subjectMissingIf a step below fails, save the error as subjectMissingTry
message.subject and save it as subjectText.Trim message.subject and save it as subjectText.subjectText isn't empty and subjectText is not nullIf subjectText isn't empty and subjectText is not nullYes
subject to subjectText.Change subject to subjectText.No
No steps
On error
A message arrived with no subject..Show in the output: A message arrived with no subject..bodyText to blank.Set bodyText to blank.bodyMissingIf a step below fails, save the error as bodyMissingTry
message.body and save it as bodyValue.Trim message.body and save it as bodyValue.bodyValue is not nullIf bodyValue is not nullYes
bodyText to bodyValue.Change bodyText to bodyValue.No
No steps
On error
A message arrived with no readable text..Show in the output: A message arrived with no readable text..seenHosts.Start an empty list and save it as seenHosts.hostLines.Start an empty list and save it as hostLines.hostCount to 0.Set hostCount to 0.linkUrl in all web addresses in bodyText:For each linkUrl in all web addresses in bodyText:hostCount is greater than or equal to hostLimit If hostCount is greater than or equal to hostLimitYes
No
No steps
linkUrl and save it as urlText. Trim linkUrl and save it as urlText.urlText starts with http:// (ignoring case) and save it as plainHttp. Check whether urlText starts with http:// (ignoring case) and save it as plainHttp.urlText split by :// with :// and save it as afterScheme. Join the items from index 1 onward of urlText split by :// with :// and save it as afterScheme.afterScheme split by / and save it as hostPart. Get the first item of afterScheme split by / and save it as hostPart.hostPart split by ? and save it as hostPart. Get the first item of hostPart split by ? and save it as hostPart.hostPart split by # and save it as hostPart. Get the first item of hostPart split by # and save it as hostPart.hostPart split by @ and save it as hostPart. Get the last item of hostPart split by @ and save it as hostPart.hostPart split by : and save it as hostPart. Get the first item of hostPart split by : and save it as hostPart.hostPart lowercase and save it as linkHost. Make hostPart lowercase and save it as linkHost.linkHost is empty or linkHost doesn't contain . or linkHost contains : or… If linkHost is empty or linkHost doesn't contain . or linkHost contains : or…Yes
No
No steps
seenHosts contains linkHost If seenHosts contains linkHostYes
No
No steps
linkHost to the end of seenHosts and save it as seenHosts. Add linkHost to the end of seenHosts and save it as seenHosts.expected to false. Set expected to false.allowed in expectedList: For each allowed in expectedList:allowed and save it as allowedName. Trim allowed and save it as allowedName.allowedName is empty or allowedName is null If allowedName is empty or allowedName is nullYes
No
No steps
linkHost is allowedName or linkHost ends with .@allowedName If linkHost is allowedName or linkHost ends with .@allowedNameYes
expected to true.Change expected to true.No
No steps
expected is yes If expected is yesYes
No
No steps
hostCount. Add 1 to hostCount.notes to blank. Set notes to blank.plainHttp is yes If plainHttp is yesYes
notes to notes [linked over plain http].Change notes to notes [linked over plain http].No
No steps
linkHost starts with xn-- or linkHost contains .xn-- If linkHost starts with xn-- or linkHost contains .xn--Yes
notes to notes [the name is written in punycode, xn--].Change notes to notes [the name is written in punycode, xn--].No
No steps
linkHost is senderDomain or linkHost ends with .@senderDomain If linkHost is senderDomain or linkHost ends with .@senderDomainYes
notes to notes [on the sender's own domain].Change notes to notes [on the sender's own domain].No
No steps
factText to nothing was looked up for this host.. Set factText to nothing was looked up for this host..linkHost isn't empty If the first match in linkHost isn't emptyYes
ipErrorIf a step below fails, save the error as ipErrorTry
linkHost. Save it as net.Get the network operator of linkHost. Save it as net.net.isp and save it as isp.Trim net.isp and save it as isp.net.autonomous_system and save it as asn.Trim net.autonomous_system and save it as asn.net.country and save it as country.Trim net.country and save it as country.the link names an address rather than a name; the registry for that address records , isp, , , asn, , , country, .] with nothing and save it as factText.Join a list of [the link names an address rather than a name; the registry for that address records , isp, , , asn, , , country, .] with nothing and save it as factText.On error
factText to the link names an address rather than a name, and the lookup for that address did not complete..Change factText to the link names an address rather than a name, and the lookup for that address did not complete..No
registryErrorIf a step below fails, save the error as registryErrorTry
linkHost. Save it as registry.Look up domain linkHost. Save it as registry.record to registry.result.Set record to registry.result.record.registration_date and save it as registeredOn.Trim record.registration_date and save it as registeredOn.record.registrar and save it as registrar.Trim record.registrar and save it as registrar.factText to the registry returned no registration date for this name..Change factText to the registry returned no registration date for this name..registeredOn isn't empty and registeredOn is not nullIf registeredOn isn't empty and registeredOn is not nullYes
ageText to blank.Set ageText to blank.ageErrorIf a step below fails, save the error as ageErrorTry
, , the difference between registeredOn and today's date in days as text, days ago] with nothing and save it as ageText.Join a list of [, , the difference between registeredOn and today's date in days as text, days ago] with nothing and save it as ageText.On error
ageText to blank.Change ageText to blank.the registry records this name as registered on , the first item of registeredOn split by T, ageText, .] with nothing and save it as factText.Join a list of [the registry records this name as registered on , the first item of registeredOn split by T, ageText, .] with nothing and save it as factText.registrar isn't empty and registrar is not nullIf registrar isn't empty and registrar is not nullYes
factText, Registrar of record: , registrar, .] with nothing and save it as factText.Join a list of [factText, Registrar of record: , registrar, .] with nothing and save it as factText.No
No steps
No
No steps
On error
factText to the registry lookup for this name did not complete..Change factText to the registry lookup for this name did not complete..- , linkHost, notes, - , factText] joined by nothing to the end of hostLines and save it as hostLines. Add a list of [- , linkHost, notes, - , factText] joined by nothing to the end of hostLines and save it as hostLines.hostLines isn't emptyIf hostLines isn't emptyYes
Links in mail that just arrived
From: , fromHeader truncated to 120 characters using ... as the ellipsis,
Subject: , subject truncated to 120 characters using ... as the ellipsis] joined by nothing, hostLines joined by a new line, Only the host part of each link is shown, and only hosts that are not on your 'expectedDomains' list. None of these lookups says what a link is - they report what the public registry holds about a name, and nothing more. A name with nothing on record is a name with nothing on record. Nothing here has visited any of these addresses.] with a blank line and save it as report.reportLink in all web addresses in report:For each reportLink in all web addresses in report:reportLink with [link removed] in report and save it as report. Replace reportLink with [link removed] in report and save it as report.report contains ://If report contains ://Yes
report to A message arrived carrying links to hosts outside your expected domains, but the report could not be written without repeating a web address from the message. Open the message in the mailbox instead..Change report to A message arrived carrying links to hosts outside your expected domains, but the report could not be written without repeating a web address from the message. Open the message in the mailbox instead..No
No steps
slackChannelId.Send a message to slackChannelId.reportpostCount.Add 1 to postCount.No
Message , messageId, linked to nothing outside your expected domains, or its text held no web addresses.] joined by nothing.Show in the output: a list of [Message , messageId, linked to nothing outside your expected domains, or its text held no web addresses.] joined by nothing.checkedLabel to email messageId.Add label checkedLabel to email messageId.readCount.Add 1 to readCount.On error
readError as text.Show in the output: Could not read the links out of one message: readError as text.Messages read: , readCount as text, , reports posted: , postCount as text] joined by nothing.Show in the output: a list of [Messages read: , readCount as text, , reports posted: , postCount as text] joined by nothing.