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 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.
Es gibt zwei Funktionen in Ihrem Skript, die drohen, dass es hängen bleibt oder eine Zeitüberschreitung auftritt:
set EveryMessage to every message of TargetInbox
Wenn dieses Postfach Tausende oder sogar Hunderte von E-Mails enthält, kann das Abrufen every message
als Liste von einzeln referenzierten message
Objekten (was diese Anweisung tut) einige Zeit dauern. Es ist fast immer viel effizienter und weniger prozessor- und speicherintensiv, a reference to
das every message
Objekt (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.
repeat
SchleifenVerschachtelte 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, repeat
obwohl 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 to
im 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 .
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:
set eachSender to the sender of eachMessage
Diese Linie wird derzeit innerhalb der inneren repeat
Schleife deklariert, die zufällig auch die fleischigere der beiden ist, im Allgemeinen hypothetisch. Dadurch wird jedoch der Wert der Variablen eachSender
fü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 eachMessage
in setzen these_message
. Das ist eine Effizienzverbesserung der polynomiellen Zeit hinab zur linearen Zeit!
set messageDate to date received of EveryMessage
Anfangs dachte ich, Sie versuchten, auf das EveryMessage
Objekt 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. EveryMessage
hier 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 received
Eigenschaft von every message of the TargetInbox
, alles über eine einzige Zeile von AppleScript.
Da Sie es derzeit nicht so implementiert haben, set messageDate
wird 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 repeat
Schleife eintritt. Und meine Vermutung dazu kennst du bereits.
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
repeat
Wie Sie sehen können, habe ich dank der Verwendung des Operators vollständig auf die innerste Schleife verzichtet a reference to
. Wie ich everyMessage
auf 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 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_rule
und ich vermute, dass dies erforderlich ist, um das these_messages
Objekt zu übergeben, das das Ergebnis der Filterung ist, die in der übergeordneten mail.app-Regel definiert ist, die das Skript aufruft.
(Am Ende der repeat
Schleife wechselte ich sender
zu 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 EveryMessage
Objekt 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. 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 eachMessage
nach 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 Rules
manuell 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 responding
ich 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!
JBis
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.Lantz Warrick
display dialog
als eine Artconsole.log
Debugging zu verwenden. Werde es versuchen.JBis