解析电子邮件的标题和日期,然后在 Things (applescript) 中创建待办事项

Parse email for title and date, then create an todo in Things (applescript)

我是 Applescript 的新手,我是根据我在网上找到的代码构建的,但无法真正让它工作。

我要做的是下面的

Apple Mail 中的一条规则将触发脚本在邮件 body 中查找 2 个文本字符串。

我想从 e-mail

中提取两件事
  1. 截止日期 (Återlämningsdatum)
  2. 书名(Title)

然后我想在 Things 中创建一个 todo,将书名作为 todo 的名称,将截止日期作为截止日期。

我 运行 现在遇到的问题是我没有从邮件中获取任何数据,只是创建了一个空的待办事项。

有什么想法吗?

E-mail低于

2017-03-22 18:43:55
MALMÖ STADSBIBLIOTEK
Stadsbiblioteket
Låntagarnummer: **********
Utlån
-------------------------
Titel: Ägg : recept & teknik / Tove Nilsson ; [fotografi: Charlie Drevstam]
Exemplarnummer: 3054550018
Återlämningsdatum: 2017-04-19
-------------------------
Antal utlånade material: 1

下面的代码

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

set subjectText to "Återlämningsdatum: "
set contentSearch to "Titel: "

using terms from application "Mail"
    on perform mail action with messages theMessages for rule theRule
        tell application "Mail"
            set theContent to content
            set theDate to my getFirstWordAfterSearchText(subjectText, theContent)
            set theTitle to my getFirstWordAfterSearchText(contentSearch, theContent)
        end tell
    end perform mail action with messages
end using terms from

tell application "Things3"
    set newToDo to make new to do
    set name of newToDo to theTitle
    set due date of newToDo to theDate
end tell

(*============== SUBROUTINES =================*)
on getFirstWordAfterSearchText(searchString, theText)
    try
        set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, searchString}
        set textItems to text items of theText
        set AppleScript's text item delimiters to tids
        return (first word of (item 2 of textItems))
    on error theError
        return ""
    end try
end getFirstWordAfterSearchText

在我的测试中,您的脚本 return 具有以下值:

theDate: "2017"
theTitle: "Ägg"

那么,我假设您或许应该得到一个名为“Ägg”的空白 to-do?如果没有,你可以试试:

    tell application "Things3" to make new to do with properties ¬
        {name: theTitle, due date: theDate}

(虽然我既不使用也不拥有 Things 3,所以无法为您测试)。

无论如何,要解决最初的问题,问题在于只要求您的处理程序 getFirstWordAfterSearchText 到 return first word。我不会说瑞典语,但在我看来,标题包含多个单词。日期肯定是这样,因为每个单词都由连字符分隔(在 AppleScript 中被视为 non-word 字符)。

我的建议是将电子邮件内容分成几个段落,将以 "Titel" 或“Återlämningsdatum”开头的文本行分开,然后是 return 这些行,排除任何不需要的词。这是执行此操作的处理程序:

    to getFirstParagraphThatStarts on searchString ¬
        from theText ¬
        apart from excludedStrings : null
        local searchString, theText, excludedStrings

        repeat with P in theText's paragraphs
            if P starts with the searchString then exit repeat
        end repeat

        set the text item delimiters to {null} & the excludedStrings
        text items of P as text
    end getFirstParagraphThatStarts

我像你一样给处理程序打电话:

    set theDate to getFirstParagraphThatStarts on subjectText from theContent
    set theTitle to getFirstParagraphThatStarts on contentSearch from theContent

(我一开始就省略了 apart from 参数,以便在实施任何排除之前测试 return 结果)。 return 结果是这样的:

theDate: "Återlämningsdatum: 2017-04-19"
theTitle: "Titel: Ägg : recept & teknik / Tove Nilsson ; [fotografi: Charlie Drevstam]"

然后我在apart from参数中加入:

    set theDate ¬
        to getFirstParagraphThatStarts on subjectText ¬
        from theContent ¬
        apart from subjectText

    set theTitle ¬
        to getFirstParagraphThatStarts on contentSearch ¬
        from theContent ¬
        apart from contentSearch

和return结果如下:

theDate: "2017-04-19"
theTitle: "Ägg : recept & teknik / Tove Nilsson ; [fotografi: Charlie Drevstam]"

认为更符合您的要求。


附录 1:日期

我对 Things 3 的另一个想法是 due date 属性 可能需要一个实际的 AppleScript date object ,而不仅仅是一个看起来像是日期的字符串。也就是说,"2017-04-19" 可能不是有效的 due date。同样,我既不使用也不拥有 Things 3,所以这只是猜测。

AppleScript 日期格式本质上与您的系统设置相关联。由于我的系统 date/time 首选项设置为使用国际 ISO-8601 日期表示,即 yyyy-mm-dd,我可以直接从 theDate 变量创建 AppleScript 日期 object,如下所示:

date theDate

如果你是这种情况,结果发现你需要一个dateobject,那么你可以简单地set due date of newToDo to date theDate,或者(如果使用我上面建议的代码):

    tell application "Things3" to make new to do with properties ¬
        {name: theTitle, due date: date theDate}

但是,如果您的系统设置不同,您将需要自己构建 AppleScript date object。这是一个可以执行此操作的处理程序:

    to makeASdate out of {year:y, month:m, day:d}
        local y, m, d

        tell (the current date) to set ¬
            [ASdate, year, its month, day, time] to ¬
            [it, y, m, d, 0]

        ASdate
    end makeASdate

然后您可以将 theDate 变量与此处理程序一起使用,如下所示:

    makeASdate out of {year:word 1, month:word 2, day:word 3} of theDate
        --> date "Wednesday, 19 April 2017 at 0:00:00"

附录 2:脚本邮件(添加于 2018-08-12)

经过进一步测试和调试后,您发现您的脚本存在其他问题,导致其无法运行。这是我的一个疏忽,因为我最初应该强调这些错误,但是我开始关注你的处理程序 returning 不完整的字符串,我忽略了回到脚本的其余部分并解决它的其他问题。

如您所见,这里是问题部分:

using terms from application "Mail"
    on perform mail action with messages theMessages for rule theRule
        tell application "Mail"
            set theContent to content
            set theDate to my getFirstWordAfterSearchText(subjectText, theContent)
            set theTitle to my getFirstWordAfterSearchText(contentSearch, theContent)
        end tell
    end perform mail action with messages
end using terms from

tell application "Mail"set theContent to content,但是,您没有指定 content 属于什么(或者,更确切地说,您已经指定 content 属于 application "Mail",它不属于。

据推测,您希望引用通过您的邮件规则发送到此脚本的 theMessagescontent

另一个要注意的主要事情是 on perform mail action with messages 是一个事件处理程序,即它响应 Mail[= 中发生的事件121=],这会导致调用处理程序。在脚本的其他地方定义其他处理程序是完全没问题的;但是具有不属于任何显式处理程序的杂散代码行将因此属于 implicit(隐藏)on run 处理程序.在某种程度上,这也是一个事件处理程序:它响应一个脚本运行,如果脚本也被要求响应一个Mail,这是有问题的同时发生事件。

因此,tell app "Things3"块需要移动,我想开头的变量声明也需要容纳。

考虑到所有这些,我在很大程度上修改了您的脚本,同时也试图使其与您的原始脚本相似,以便在一定程度上可以识别:

    using terms from application "Mail"
        on perform mail action with messages theMessages for rule theRule
            set dateToken to "Återlämningsdatum: "
            set titleToken to "Titel: "

            repeat with M in theMessages
                set theContent to getMessageContent for M

                set datum to restOfLineMatchedAtStart by dateToken from theContent
                set titel to restOfLineMatchedAtStart by titleToken from theContent

                if false is not in [datum, titel] then
                    set D to makeASdate out of (datum's words as list)
                    createToDoWithDueDate on D given name:titel
                end if
            end repeat

        end perform mail action with messages
    end using terms from


    to makeASdate out of {Y, M, D}
        local Y, M, D

        tell (the current date) to set ¬
            [ASdate, year, its month, day, time] to ¬
            [it, Y, M, D, 0]

        ASdate
    end makeASdate


    to createToDoWithDueDate on D as date given name:N as text
        tell application "Things3" to make new to do ¬
            with properties {name:N, due date:D}
    end createToDoWithDueDate


    to getMessageContent for msg
        local msg

        tell application "Mail" to return msg's content
    end getMessageContent


    on restOfLineMatchedAtStart by searchString from theText
        local searchString, theText

        ignoring white space
            repeat with P in theText's paragraphs
                if P starts with the searchString then
                    set i to (length of searchString) + (offset of searchString in P)
                    try
                        return text i thru -1 of P
                    on error -- matched entire line
                        return ""
                    end try
                end if
            end repeat
        end ignoring

        false -- no match
    end restOfLineMatchedAtStart

现在,由于我不使用 Mail 并且无法自行测试这些邮件规则,您可能会发现需要进行一两个小调整在 运行 正常之前。另一方面,它可能 运行 正确,这会让我感到惊讶。但是,在花了很多时间思考每一行代码之后,我希望它接近您的需要。

您可以看到的主要变化是现在每段代码都属于一个处理程序。每个自定义处理程序都从主事件处理程序 on perform mail action with messages 内部调用。我还更改了一些变量名,主要是作为我正在进行的心理调试的一部分(我更改了几次,并将它们留给 w他们最后一个有意义的标签就在我的脑海里。

让我知道进展如何。报告任何错误。

注意: 但是不要忘记,此脚本旨在由 Mail 应用程序调用以响应正在执行的邮件规则。 运行 它来自 脚本编辑器 不会做任何事情。