Creé una regla para mover el correo de remitentes específicos a un nuevo buzón llamado "Noticias". Me gustaría que mi AppleScript pasara por la carpeta "Noticias" y solo mantuviera el emaisa más reciente de esos remitentes, eliminando los mensajes anteriores. (Esto es como una de las funciones de barrido en MSLive/Outlook). Intenté escribir un script de la siguiente manera, que es invocado por la regla:
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
Veo que la secuencia de comandos es llamada por la regla, debido al engranaje giratorio en la barra de menú, pero no se produce ninguna de las eliminaciones deseadas, y la secuencia de comandos parece colgarse en una especie de bucle.
Soy un AppleScript n00b, lo hago mucho mejor con JavaScript. Agradecería cualquier ayuda.
Gracias, Betalant
macos 10.13.5 | Correo 11.4 | AppleScript 2.7
No uso Mail.app y no tengo mucha experiencia en la implementación de acciones de Mail , por lo que no estoy en condiciones de probar su script. Sin embargo, al leerlo, hay lugares en él de posible preocupación que me gustaría mirar primero al depurar.
Hay dos características en su secuencia de comandos que amenazan con colgar o expirar el tiempo de espera:
set EveryMessage to every message of TargetInbox
Si ese buzón tiene miles o incluso cientos de correos electrónicos, la recuperación every message
como una lista de message
objetos a los que se hace referencia individualmente (que es lo que hace esta declaración) podría llevar algún tiempo. Casi siempre es mucho más eficiente y menos intensivo en el uso del procesador y la memoria para almacenar a reference to
el every message
objeto (colección):
set EveryMessage to a reference to every message of the TargetInbox
Tiene otra característica beneficiosa que abordaré más adelante.
repeat
2. Bucles anidados potencialmente exigentesLos bucles anidados son a veces un mal necesario, pero la consulta sobre el tamaño del buzón es, nuevamente, una fuente de ansiedad para mí, especialmente porque se encuentra en el corazón del nido donde se realiza la mayor parte de las operaciones. Esto significa que, para cada nuevo mensaje que activa el script, cada uno de los mensajes del buzón debe comprobarse y compararse con el mensaje activador.
Estas son dos ramas de un mismo problema, realmente, porque si su buzón solo tiene 5 mensajes, nada de esto es particularmente molesto. De lo contrario, primero obtendrá AppleScript para recuperar todos los mensajes en el buzón y almacenarlos en una variable; luego recorre esta carga potencialmente pesada y compara cada elemento con otro.
Si no tuvo más remedio que usar un repeat
bucle sabiendo que tendría que iterar a través de muchos elementos de la lista (una vez que supere los 500 de cualquier cosa, AppleScript puede comenzar a fallar), puede ayudar, una vez más, pasar AppleScript un referencia a la lista de elementos en lugar de la lista real. Pasar cualquier referencia a través de un objeto de secuencia de comandos (que es lo que a reference to
esencialmente se hace) es mucho, mucho más rápido que hacer que AppleScript acceda a un objeto por otros medios. Aquí hay una excelente explicación y demostración de estos principios .
Después de abordar el gran problema anterior, que podría resultar de poca relevancia para su caso particular, aquí hay uno o dos elementos de facto que se pueden cambiar fácilmente para mejorar la eficiencia de la secuencia de comandos o evitar que arroje un error:
set eachSender to the sender of eachMessage
Esta línea se declara actualmente dentro del repeat
bucle interno, que también resulta ser el más carnoso de los dos, en términos generales hipotéticos. Sin embargo, lo que está haciendo es establecer el valor de la variable eachSender
en el mismo valor para tantos mensajes que tenga en su buzón. Esas son muchas operaciones desperdiciadas para AppleScript (un total del número de these_messages
multiplicado por el número de EveryMessage
).
En su lugar, muévelo aquí:
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
Ahora AppleScript solo tiene que establecer la variable una vez eachMessage
en these_message
. ¡Esa es una mejora de la eficiencia del tiempo polinomial hasta el tiempo lineal!
set messageDate to date received of EveryMessage
Inicialmente, pensé que estaba tratando de acceder al EveryMessage
objeto como una referencia a la colección de la que hablé anteriormente, y simplemente no me di cuenta de que no podía hacerlo de la forma en que declaró EveryMessage
.
Pero ahora me doy cuenta de que lo más probable es que solo tus manos escribieran más rápido que tus pensamientos e introdujeran un molesto error tipográfico. EveryMessage
aquí debería ser this_message
, es decir:
set messageDate to date received of this_message
Esto me lleva muy bien a mi punto final, que insinué anteriormente, con respecto al otro beneficio de declarar una variable a una colección de objetos como referencia.
Si hubieras hecho esto:
set EveryMessage to a reference to every message of the TargetInbox
luego esto:
set messageDate to date received of EveryMessage
sería una pieza perfectamente válida de AppleScript, que le permite acceder a la propiedad de cada uno de los elementos de una lista IFF a través de una referencia a esa lista antes de que se produzca cualquier tipo de desreferenciación. Una vez que se elimina la referencia, la lista se evalúa en referencias de objetos individuales y ya no le dará los medios para enumerar a través de sus propiedades de esa manera.
Lo que obtiene si se hace correctamente es una lista que contiene los valores de la date received
propiedad de every message of the TargetInbox
, todo a través de una sola línea de AppleScript.
Actualmente, como no fue así como lo implementó, la declaración definitivamenteset messageDate
generará un error.
Esto explica por qué no se produce ninguna de las eliminaciones, porque su secuencia de comandos nunca alcanzará con éxito esa parte. Sin embargo, el error ocurriría de inmediato, por lo que creo que el script ni siquiera llega a esa línea, ni siquiera una vez. Por lo tanto, el problema debe originarse en un punto de la secuencia de comandos antes de que entre con éxito en el repeat
bucle interno. Y ya conoces mi corazonada al respecto.
Lamento no poder probar mi secuencia de comandos para verificar que definitivamente funcionará la primera vez sin ningún ajuste, así que dime cómo te va con esto:
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
Como puede ver, eliminé por completo el repeat
bucle más interno gracias al uso del a reference to
operador. Como dije everyMessage
de esa manera, puedo (con suerte) enumerar las propiedades de todos los elementos que contiene la lista de una sola vez, lo que debería ser aproximadamente infinitas veces más rápido que tener que verificar la propiedad de cada elemento individualmente.
Muchas gracias a @CJK por una respuesta tan completa. Su solución funciona con solo un ajuste y también aprendí algunos conceptos básicos para AppleScript. El siguiente script de trabajo ahora se ejecuta con bastante rapidez:
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
La secuencia de comandos parecía no ejecutarse sin la adición en la línea 2 for rule this_rule
y supongo que es necesario para pasar el these_messages
objeto que es el resultado del filtrado definido en la regla principal mail.app que invoca la secuencia de comandos.
(Al final del repeat
ciclo, cambié sender
a reply to
para manejar las instancias en las que el remitente había cambiado su cadena de autoidentificación en la cuenta de envío, aunque la dirección real seguía siendo la misma, lo que provocó que el script no viera correos electrónicos más antiguos de la misma dirección).
La comprensión clave que me faltaba es que el EveryMessage
objeto no se pasó automáticamente por referencia. Vengo de JavaScript, donde los objetos, matrices y variables se pasan automáticamente por referencia, mientras que en AppleScript uno debe declararlo como un objeto de referencia.
Me he encontrado con un par de problemas más al implementar este script.
Esta es la regla que ejecuta mi script. Tenga en cuenta que el comando 'mover' siempre se ejecuta antes que el script, incluso si intento colocarlo después del comando de ejecución del script. Mail.app no parecía ejecutar la secuencia de comandos, y pensé que podría deberse a mover primero el mensaje entrante al buzón de destino y luego ejecutar la secuencia de comandos en el buzón de destino. Dado que la secuencia de comandos compara los mensajes entrantes ( eachMessage in these_messages
) con los mensajes en el buzón de correo de destino ( everyMessage
), ¿quizás no quedan eachMessage
objetos después del movimiento ejecutado para usar en la secuencia de comandos? Para probar mi teoría, decidí incorporar el comando mover en mi secuencia de comandos, de la siguiente manera:
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
Entonces ahora mi regla solo ejecuta mi script en los mensajes entrantes apropiados. El problema ahora es que, si accedo Apply Rules
manualmente a un mensaje desde el menú de mail.app, el script se ejecuta como se esperaba, pero cuando la regla se ejecuta automáticamente en los mensajes entrantes, mail.app se cuelga, es decir, not responding
tengo que forzar el cierre y reiniciar, a veces primero deshabilitando el script. Pensé que podría deberse a que había más de 100 mensajes en el buzón de destino, pero luego los limpié para tener solo ~ 50 mensajes, y el bloqueo persiste.
¡Agradecería mucho cualquier ayuda, de @CJK o de cualquier persona!
JBis
display dialog "Hi"
, que es como el equivalente de JavaScript de alerta ("Hola"), en las repeticiones para verificar si reaparecen correctamente. Luego cambia Hola con una variable que usa (comothis_message
) para asegurarse de que la variable sea correcta.Lantz Warrick
display dialog
como una especie deconsole.log
depuración. Le daría una oportunidad.JBis