Helfen Sie beim Schreiben von AppleScript mit der Mail-Regel, um auf dem neuesten Stand zu bleiben

Ich habe eine Regel erstellt, um E-Mails von bestimmten Absendern in ein neues Postfach namens „News“ zu verschieben. Ich möchte, dass mein AppleScript den Ordner "News" durchläuft und nur die neuesten E-Mails von diesen Absendern behält und vorherige Nachrichten löscht. (Dies ist wie eine der Sweep-Funktionen in MSLive/Outlook.) Ich habe versucht, ein Skript wie folgt zu schreiben, das von der Regel aufgerufen wird:

using terms from application "Mail"
    on perform mail action with messages these_messages for rule this_rule
        tell application "Mail"
            set dateToday to current date
            set TargetInbox to mailbox "News" of account "iCloud"
            set EveryMessage to every message of TargetInbox
            repeat with eachMessage in these_messages
                repeat with this_message in EveryMessage
                    set eachSender to the sender of eachMessage
                    set this_sender to the sender of this_message
                    set messageDate to date received of EveryMessage
                    if messageDate < dateToday and eachSender = this_sender then
                        delete this_message
                    end if
                end repeat
            end repeat
        end tell
    end perform mail action with messages
end using terms from

Ich sehe, dass das Skript wegen des sich drehenden Zahnrads in der Menüleiste von der Regel aufgerufen wird, aber keine der gewünschten Löschungen erfolgt, und das Skript scheint in einer Art Schleife zu hängen.

Ich bin ein AppleScript n00b, komme viel besser mit JavaScript zurecht. Ich würde mich über jede Hilfe freuen.

Danke Betalantz

macOS 10.13.5 | E-Mail 11.4 | AppleScript 2.7

Ich werde später noch einmal ausführlicher darauf eingehen. Aber was ich gerne mache, ist jeden Teil eines Skripts zu testen. Beispielsweise können Sie display dialog "Hi"in den Wiederholungen , das wie das JavaScript-Äquivalent von alert("Hi") ist, verwenden, um zu überprüfen, ob sie wieder korrekt erscheinen. Dann ersetzen Sie Hi durch eine Variable, die Sie verwenden (z. B. this_message), damit Sie sicherstellen können, dass die Variable korrekt ist.
Toller Tipp, display dialogals eine Art console.logDebugging zu verwenden. Werde es versuchen.
Es gibt auch eine Konsolenoption in AppleScript, aber ich bevorzuge immer Dialoge. :)

Antworten (3)

Ich verwende Mail.app nicht und habe nicht viel Erfahrung mit der Implementierung von Mail-Aktionen , daher bin ich nicht in der Lage, Ihr Skript zu testen. Beim Durchlesen gibt es jedoch potenziell bedenkliche Stellen, auf die ich beim Debuggen zuerst achten möchte.

Wie groß ist Ihr "News" -Postfach?

Es gibt zwei Funktionen in Ihrem Skript, die drohen, dass es hängen bleibt oder eine Zeitüberschreitung auftritt:

1.set EveryMessage to every message of TargetInbox

Wenn dieses Postfach Tausende oder sogar Hunderte von E-Mails enthält, kann das Abrufen every messageals Liste von einzeln referenzierten messageObjekten (was diese Anweisung tut) einige Zeit dauern. Es ist fast immer viel effizienter und weniger prozessor- und speicherintensiv, a reference todas every messageObjekt (Sammlung) zu speichern:

set EveryMessage to a reference to every message of the TargetInbox

Es hat eine weitere vorteilhafte Funktion, auf die ich später eingehen werde.

2. Potenziell anspruchsvolle verschachtelte repeatSchleifen

Verschachtelte Schleifen sind manchmal ein notwendiges Übel, aber die Abfrage nach der Größe des Postfachs bereitet mir wieder einmal Sorgen, zumal sie im Herzen des Nests aufgerufen wird, wo der Großteil der Operationen durchgeführt wird. Das bedeutet, dass für jede neue Nachricht, die das Skript auslöst, jede einzelne Nachricht im Postfach überprüft und mit der Triggernachricht verglichen werden muss.

Das sind wirklich zwei Zweige eines Problems, denn wenn Ihr Postfach nur 5 Nachrichten enthält, ist das alles nicht besonders störend. Andernfalls erhalten Sie zuerst AppleScript, um jede Nachricht in der Mailbox abzurufen und sie in einer Variablen zu speichern. dann durchlaufen Sie diese potenziell schwere Last und vergleichen jedes Element mit einem anderen.

Wenn Sie keine andere Wahl hätten, als eine Schleife zu verwenden, repeatobwohl Sie wissen, dass sie viele Listenelemente durchlaufen müsste (sobald Sie etwa 500 von irgendetwas überschreiten, kann AppleScript anfangen zu knicken), kann es wieder einmal helfen, AppleScript a zu übergeben Verweis auf die Artikelliste anstelle der eigentlichen Liste. Jede Referenz durch ein Skriptobjekt zu leiten (was a reference toim Wesentlichen der Fall ist), ist viel, viel schneller, als AppleScript auf andere Weise auf ein Objekt zugreifen zu lassen. Hier ist eine hervorragende Erklärung und Demonstration dieser Prinzipien .

Einfache Änderungen und Fehlerkorrekturen

Nachdem Sie das schwere Problem oben angesprochen haben, das sich für Ihren speziellen Fall als wenig relevant herausstellen könnte, sind hier ein oder zwei De-facto-Elemente, die leicht geändert werden können, um entweder die Effizienz des Skripts zu verbessern oder zu verhindern, dass es einen Fehler auslöst:

1. Platzierung von Variablendeklarationen

set eachSender to the sender of eachMessage

Diese Linie wird derzeit innerhalb der inneren repeatSchleife deklariert, die zufällig auch die fleischigere der beiden ist, im Allgemeinen hypothetisch. Dadurch wird jedoch der Wert der Variablen eachSenderfür so viele Nachrichten in Ihrem Postfach auf denselben Wert gesetzt. Das sind viele verschwendete Operationen für AppleScript (insgesamt die Anzahl von these_messages multipliziert mit der Anzahl von EveryMessage).

Verschieben Sie es stattdessen hierher:

repeat with eachMessage in these_messages
    set eachSender to the sender of eachMessage  # ...now it's here
    repeat with this_message in EveryMessage
        # It was here...
        .
        .
        .
    end repeat
end repeat

Jetzt muss AppleScript die Variable nur einmal für eachMessagein setzen these_message. Das ist eine Effizienzverbesserung der polynomiellen Zeit hinab zur linearen Zeit!

2.set messageDate to date received of EveryMessage

Anfangs dachte ich, Sie versuchten, auf das EveryMessageObjekt als Referenz auf die Sammlung zuzugreifen, von der ich zuvor gesprochen hatte, und wussten einfach nicht, dass Sie dies nicht auf die von Ihnen angegebene Weise tun konnten EveryMessage.

Aber mir ist jetzt klar, dass es höchstwahrscheinlich nur Ihre Hände waren, die schneller als Ihre Gedanken tippen und einen lästigen Tippfehler einführten. EveryMessagehier sollte stehen this_message, dh:

set messageDate to date received of this_message

Dies führt mich ganz schön zu meinem letzten Punkt, auf den ich bereits angedeutet habe, in Bezug auf den anderen Vorteil, eine Variable für eine Objektsammlung als Referenz zu deklarieren.

Hättest du das gemacht:

set EveryMessage to a reference to every message of the TargetInbox

dann das:

set messageDate to date received of EveryMessage

wäre ein vollkommen gültiges Stück AppleScript, mit dem Sie auf die Eigenschaft jedes einzelnen Elements in einer Liste zugreifen können, indem Sie dies durch eine Referenz auf diese Liste tun, bevor irgendeine Art von Dereferenzierung stattgefunden hat. Nach der Dereferenzierung wird die Liste in einzelne Objektreferenzen ausgewertet, und Sie haben nicht mehr die Möglichkeit, ihre Eigenschaften auf diese Weise aufzuzählen.

Was Sie erhalten, wenn Sie es richtig machen, ist eine Liste mit den Werten der date receivedEigenschaft von every message of the TargetInbox, alles über eine einzige Zeile von AppleScript.

Da Sie es derzeit nicht so implementiert haben, set messageDatewird die Deklaration für definitiv einen Fehler auslösen.

Dies erklärt, warum keine der Löschungen auftreten, da Ihr Skript diesen Teil niemals erfolgreich erreichen wird. Der Fehler würde jedoch sofort auftreten, daher habe ich das Gefühl, dass das Skript diese Zeile auch nicht einmal erreicht, nicht einmal. Daher muss das Problem an einer Stelle im Skript entstehen, bevor es jemals erfolgreich in die innere repeatSchleife eintritt. Und meine Vermutung dazu kennst du bereits.

Nun zu einer möglichen Lösung

Es tut mir leid, dass ich mein Skript nicht wirklich testen kann, um zu überprüfen, ob dies definitiv beim ersten Mal ohne Änderungen funktioniert, also sagen Sie mir, wie Sie damit zurechtkommen:

    using terms from application "Mail"
        on perform mail action with messages these_messages
            tell application "Mail"
                set everyMessage to a reference to messages in mailbox "News" of account "iCloud"
                repeat with eachMessage in these_messages
                    delete (everyMessage where ¬
                        the date received is not the (current date) ¬
                        and its sender is the sender of eachMessage)
                end repeat
            end tell
        end perform mail action with messages
    end using terms from

repeatWie Sie sehen können, habe ich dank der Verwendung des Operators vollständig auf die innerste Schleife verzichtet a reference to. Wie ich everyMessageauf diese Weise erklärt habe, bin ich (hoffentlich) in der Lage, die Eigenschaften aller Elemente der Liste auf einmal aufzuzählen, was ungefähr unendlich viel schneller sein sollte, als die Eigenschaft für jedes Element einzeln zu überprüfen.

Vielen Dank an @CJK, dass Sie nicht nur eine gute Lösung angeboten, sondern auch so gründlich erklärt haben, dass ich wertvolle Aspekte von AppleScript gelernt habe! Meine vollständige Antwort finden Sie in meinem Kommentar zu diesem Beitrag.
@LantzWarrick Immer gut, um die Perspektive eines zweiten Programmierers zu bekommen, selbst wenn Ihr Code funktioniert. Sie haben vielleicht einen anderen Ansatz, der besser ist, und selbst wenn es nicht besser ist, werden Sie einen anderen Weg sehen, das Problem zu lösen. Oft gibt es viele, viele Möglichkeiten, ein Problem zu lösen. Lernen Sie weiter AppleScript, wir können immer kreative Programmierer verwenden!
"sollte ungefähr unendlich mal schneller sein" 😂😂😂 👍

Vielen Dank an @CJK für eine so gründliche Antwort. Ihre Lösung funktioniert mit nur einer Optimierung, und ich habe auch einige Kernkonzepte für AppleScript gelernt. Das folgende Arbeitsskript wird jetzt ziemlich schnell ausgeführt:

using terms from application "Mail"
    on perform mail action with messages these_messages for rule this_rule
        tell application "Mail"
            set everyMessage to a reference to messages in mailbox "News" of account "iCloud"
            repeat with eachMessage in these_messages
                delete (everyMessage where ¬
                    the date received is not the (current date) ¬
                    and its reply to is the reply to of eachMessage)
            end repeat
        end tell
    end perform mail action with messages
end using terms from

Das Skript schien ohne die Hinzufügung von in Zeile 2 nicht ausgeführt zu werden, for rule this_ruleund ich vermute, dass dies erforderlich ist, um das these_messagesObjekt zu übergeben, das das Ergebnis der Filterung ist, die in der übergeordneten mail.app-Regel definiert ist, die das Skript aufruft.

(Am Ende der repeatSchleife wechselte ich senderzu reply to, um Fälle zu behandeln, in denen der Absender seine Selbstidentifikationszeichenfolge auf dem sendenden Konto geändert hatte, obwohl die tatsächliche Adresse dieselbe blieb, was dazu führte, dass das Skript ältere E-Mails von derselben Adresse übersah.)

Das wichtigste Verständnis, das ich vermisst habe, ist, dass das EveryMessageObjekt nicht automatisch als Referenz übergeben wurde. Ich komme aus JavaScript, wo Objekte, Arrays und Variablen automatisch per Referenz übergeben werden, während man sie in AppleScript als Referenzobjekt deklarieren muss.

Ich bin bei der Implementierung dieses Skripts auf ein paar weitere Probleme gestoßen.Dies ist die Regel, die mein Skript ausführt.

Dies ist die Regel, die mein Skript ausführt. Beachten Sie, dass der Befehl „move“ immer vor dem Skript ausgeführt wird, selbst wenn ich versuche, ihn nach dem Befehl zur Skriptausführung zu platzieren. Mail.app schien das Skript nicht auszuführen, und ich dachte, es könnte dadurch verursacht werden, dass die eingehende Nachricht zuerst in das Zielpostfach verschoben und dann das Skript im Zielpostfach ausgeführt wird. Da das Skript die eingehenden Nachrichten ( eachMessage in these_messages) mit Nachrichten im Zielpostfach ( everyMessage) vergleicht, sind eachMessagenach dem Verschieben möglicherweise keine Objekte mehr vorhanden, die im Skript verwendet werden könnten? Um meine Theorie zu testen, habe ich beschlossen, den Move-Befehl wie folgt in mein Skript zu integrieren:

using terms from application "Mail"
    on perform mail action with messages these_messages for rule this_rule
        tell application "Mail"
            set everyMessage to a reference to messages in mailbox "Charitable appeals" of account "iCloud"
            repeat with eachMessage in these_messages
                delete (everyMessage where ¬
                    the date received is not the (current date) ¬
                    and (its sender is the sender of eachMessage ¬
                    or its reply to is equal to the reply to of eachMessage))
            end repeat
            repeat with eachMessage in these_messages
                move eachMessage to mailbox "Charitable appeals" of account "iCloud"
            end repeat
        end tell
    end perform mail action with messages
end using terms from

Also führt meine Regel jetzt mein Skript nur für die entsprechenden eingehenden Nachrichten aus. Das Problem ist jetzt, dass, wenn ich Apply Rulesmanuell eine Nachricht aus dem Menü von mail.app ausführe, das Skript wie erwartet ausgeführt wird, aber wenn die Regel bei eingehenden Nachrichten automatisch ausgeführt wird, dass mail.app hängt, muss not respondingich manchmal das Beenden und Neustarten erzwingen Deaktivieren Sie zuerst das Skript. Ich dachte, es könnte daran liegen, dass sich über 100 Nachrichten im Zielpostfach befanden, aber dann habe ich sie bereinigt, sodass nur noch ~50 Nachrichten vorhanden sind, und das Hängen bleibt bestehen.

Ich würde mich sehr über jede Hilfe freuen, von @CJK oder sonst jemandem!