with the very kind help of the members here I succeeded to build a script, that saves every incoming Mail message as .eml file.
In Apple Mail I built a rule to target the script to special mails.
But…
I’d like to be more specific than what’s possible with Apple mail rules.
In the beginning of the script I’d like to check wether the subject of the mail matches a certain pattern. And for the pattern I have built a regex expression.
Question:
(how) is it possible to check at the beginning of the script if the subject matches the regex - if positive perform the script or otherwise quit the script?
The regex expression identifies mail subjects that look like:
ubfg-210312-gg-proposal for contract
The expression is: (x|(w-))?[^-]…-\d{6,6}-\w\w-.{0,}
The script is:
global theFile
using terms from application "Mail"
on perform mail action with messages these_messages for rule this_rule
tell application "Mail"
repeat with eachMessage in these_messages
set ptd to alias "Macintosh HD:Users:xy:Documents:mail_deposit:"
set theText to source of eachMessage
set theSubject to (subject of eachMessage) -- as string
if theSubject is "" then set theSubject to "no subject"
if theSubject contains ":" then ¬
set theSubject to my snr(theSubject, ":", "_")
set theFile to ((ptd & theSubject) & ".eml") as string
-- display dialog "File" & (theFile as string)
my resolveConflict(ptd, theSubject)
set theFileID to open for access file theFile with write permission
write theText to theFileID
close access theFileID
end repeat
-- display dialog "There were " & length of these_messages & " messages saved."
end tell
end perform mail action with messages
end using terms from
on resolveConflict(ptd, theSubject)
tell application "Finder"
set theCounter to 1
set noConflict to false
repeat until noConflict
if exists file (theFile) then
set theFile to (((ptd & theSubject) & " -" & theCounter as string) & ".eml")
set theCounter to theCounter + 1
else
set noConflict to true
end if
end repeat
end tell
end resolveConflict
on snr(theString, searchString, replaceString)
tell (a reference to my text item delimiters)
set {oldTID, contents} to {contents, searchString}
set {theString, contents} to {theString's text items, replaceString}
set {theString, contents} to {theString as Unicode text, oldTID}
end tell
return theString
end snr
Test yourself. I edited your resolveConflict handler as well. And, I removed your snr handler, because your subjects doesn’t contain “:” symbol. Script:
use AppleScript version "2.5"
use framework "Foundation"
use scripting additions
property NSString : a reference to current application's NSString
property NSRegularExpressionSearch : a reference to current application's NSRegularExpressionSearch
property ptd : ((path to documents folder) as text) & "mail_deposit:"
property theRegex : "(x|(w-))?[^-]...-\\d{6,6}-\\w\\w-.{0,}"
using terms from application "Mail"
on perform mail action with messages these_messages for rule this_rule
tell application "Mail"
repeat with eachMessage in these_messages
tell eachMessage to set theSubject to its subject
-- CHECK matchinng to Regex
set theNSString to (NSString's stringWithString:theSubject)
set subject_MatchesToRegex to (theNSString's rangeOfString:theRegex options:NSRegularExpressionSearch)'s |length|() > 0
-- EXPORT as EML file if subject matches to regex
if subject_MatchesToRegex then
tell eachMessage to set theText to its source
set theFile to my resolveConflict(ptd, theSubject)
set theFileID to open for access file theFile with write permission
write theText to theFileID
close access theFileID
end if
end repeat
end tell
end perform mail action with messages
end using terms from
on resolveConflict(ptd, theSubject)
tell application "Finder"
set theCounter to 1
repeat
set theFile to ptd & theSubject & " -" & theCounter & ".eml"
if not (exists file theFile) then return theFile
set theCounter to theCounter + 1
end repeat
end tell
end resolveConflict
Thank you KniazidisR, the code looks beautiful.
Strangely I didn’t get it to work in my environment. Maybe I made some mistake while transferring it?
I added 2 dialogs for debugging but I couldn’t identify the problem.
When the Script gets triggered I get the first dialog telling me “Start repeat loop.” but then the script seems to stop and the second dialog “Begin check matching.” does no appear at all.
Another thing: is there a way to display the result of the check for debugging issues. Just for the case if I made some mistake with my regex expression. I already tested it at https://regex101.com/ but maybe I made some mistake by transferring it to AppleScript.
use AppleScript version "2.5"
use framework "Foundation"
use scripting additions
property NSString : a reference to current application's NSString
property NSRegularExpressionSearch : a reference to current application's NSRegularExpressionSearch
property ptd : ((path to documents folder) as text) & "mail_deposit:"
property theRegex : "(x|(w-))?[^-]...-\\d{6,6}-\\w\\w-.{0,}"
using terms from application "Mail"
on perform mail action with messages these_messages for rule this_rule
tell application "Mail"
repeat with eachMessage in these_messages
display dialog "Start repeat loop."
tell eachMessage to set theSubject to its subject
display dialog "Begin check matching."
-- CHECK matchinng to Regex
set theNSString to (NSString's stringWithString:theSubject)
set subject_MatchesToRegex to (theNSString's rangeOfString:theRegex options:NSRegularExpressionSearch)'s |length|() > 0
-- EXPORT as EML file if subject matches to regex
if subject_MatchesToRegex then
display dialog "Subject matches."
tell eachMessage to set theText to its source
set theFile to my resolveConflict(ptd, theSubject)
set theFileID to open for access file theFile with write permission
write theText to theFileID
close access theFileID
end if
end repeat
end tell
end perform mail action with messages
end using terms from
on resolveConflict(ptd, theSubject)
set theFile to ptd & theSubject & ".eml"
set theCounter to 0
repeat
try
alias theFile
return theFile
on error
set theCounter to theCounter + 1
set theFile to ptd & theSubject & " -" & theCounter & ".eml"
end try
end repeat
end resolveConflict
Display dialog is modal and waits response from you. And may be hidden on the background. Try to put instead display notification for debugging. For example:
display notification "Start repeat loop." giving up after 2 -- seconds
delay 3
Or, put after tell application “Mail” following, to bring Mail’s window and display dialogs to front:
activate
To debug result of check, you can use:
if subject_MatchesToRegex then display notification "Subject Matches To Regex" giving up after 2
delay 3
I add a delay of 3 seconds (which should be slightly longer than the notification’s self-disappearance time), because if the script is too fast, the notifications may overlap. And we need clarity when debugging.
Now,
here, I check the subject provided by you in the post #1, and script returns true:
use AppleScript version "2.5"
use framework "Foundation"
use scripting additions
property NSString : a reference to current application's NSString
property NSRegularExpressionSearch : a reference to current application's NSRegularExpressionSearch
property theRegex : "(x|(w-))?[^-]...-\\d{6,6}-\\w\\w-.{0,}"
set theSubject to "ubfg-210312-gg-proposal for contract"
set theNSString to (NSString's stringWithString:theSubject)
set subject_MatchesToRegex to (theNSString's rangeOfString:theRegex options:NSRegularExpressionSearch)'s |length|() > 0
--> true
First of all I tried to implement the notification alerts but it only get’s me an error telling me something like ‘end of line expected but identifier found’. Maybe it’s because I have BigSur with AppleScript 2.7. If I replace the word ‘notification’ by ‘dialog’ there is no error, but then I have a dialog again.
Next I tried ‘activate’ but this doesn’t reveal any hidden dialog boxes.
And then I tried all kinds of modifications to get the script working, but nothing worked.
So I tried again the script version with the two dialogs but still the same.
It shows the dialog “Start repeat loop.” but then it seem’s to stop.
The next dialog “Begin check matching.” right after the line “tell eachMessage to set theSubject to its subject” does not appear and the small turning gear icon in the menue stops and then disappears.
Do you have any idea if maybe the other AppleScript version is causing this problem?
First, my resolveConlict handler contained an error. I fixed it now.
Secondly, the script is easier to debug not as a mail rule, but as a regular script. To do this, just comment out the line on/end perform mail actions and use (get selection) instead of these_messages.
I tested the following script, edited as regular script and it works. It is easy for you to turn this script to mail rule. If it does not work in the form of a rule, then the reason will no longer be in the script, but in the Mail’s bug with mail rules. So, debug version script:
use AppleScript version "2.5"
use framework "Foundation"
use scripting additions
property NSString : a reference to current application's NSString
property NSRegularExpressionSearch : a reference to current application's NSRegularExpressionSearch
property ptd : ((path to documents folder) as text) & "mail_deposit:"
property theRegex : "(x|(w-))?[^-]...-\\d{6,6}-\\w\\w-.{0,}"
using terms from application "Mail"
-- on perform mail action with messages these_messages for rule this_rule (COMMENTED)
tell application "Mail"
repeat with eachMessage in (get selection) -- these_messages (EDITED)
tell eachMessage to set theSubject to its subject
-- CHECK matchinng to Regex
set theNSString to (NSString's stringWithString:theSubject)
set subject_MatchesToRegex to (theNSString's rangeOfString:theRegex options:NSRegularExpressionSearch)'s |length|() > 0
-- EXPORT as EML file if subject matches to regex
if subject_MatchesToRegex then
tell eachMessage to set theText to (its source) as rich text
set theFile to my resolveConflict(ptd, theSubject)
set theFileID to open for access file theFile with write permission
write theText to theFileID
close access theFileID
end if
end repeat
end tell
-- end perform mail action with messages (COMMENTED)
end using terms from
on resolveConflict(ptd, theSubject)
tell application "Finder"
set theCounter to 1
repeat
set theFile to ptd & theSubject & " -" & theCounter & ".eml"
if not (exists file theFile) then return theFile
set theCounter to theCounter + 1
end repeat
end tell
end resolveConflict
The script is now working perfectly. As a ‘normal’ script and as a script attached to a mail rule as well.
Very good hint to test it as a ‘normal’ script for debugging.
This will sure help me in the future although in this case no debugging was needed because it all worked well without any adjustments.
Just curious…
Is there a way to extract the string, that is found by the regex search?
In this actual case it might not make sense. But if the subject only ‘contains’ a string that matches the regex expression it might make sense to be able to work with the string.
For example: if the subject of the mail was…
Re.: Re.: Re.: ubfg-210312-gg-proposal for contract
… it might help to extract ‘ubfg-210312-gg-proposal for contract’
I tried this by:
set extraktString to (theNSString's rangeOfString:theRegex options:NSRegularExpressionSearch)
display dialog "extraktString " & (extraktString as rich text)
rangeOfString:options: returns an NSRange, a struct with a location and a length, you have to extract the string with subStringWithRange
set extraktRange to (theNSString's rangeOfString:theRegex options:NSRegularExpressionSearch)
tell current application to set extraktString to (theNSString's subStringWithRange:extraktRange) as text
display dialog "extraktString " & extraktString
The tell current application expression avoids the terminology clash text <–> rich text
use AppleScript version "2.5"
use framework "Foundation"
use scripting additions
property NSString : a reference to current application's NSString
property NSRegularExpressionSearch : a reference to current application's NSRegularExpressionSearch
property ptd : ((path to documents folder) as text) & "mail_deposit:"
property theRegex : "(x|(w-))?[^-]...-\\d{6,6}-\\w\\w-.{0,}"
set theNSString to (NSString's stringWithString:"ubfg-210312-gg-proposal for contract")
set extraktRange to (theNSString's rangeOfString:theRegex options:NSRegularExpressionSearch)
set extraktString to (theNSString's substringWithRange:extraktRange) as string -- EDITED
display dialog "extraktString: \"" & extraktString & "\""