Archive for the 'Mail.app' Category

2017/01/23 Mail.appで選択中のメッセージからソースを取得してMailCoreで再組み立てして解釈

Mail.appに対してメール(message)の各種属性を問い合わせるのと、Mail.appからメール(message)のソースを取得して、オープンソースのフレームワーク「mailcore2」で各種属性を取得するのとでどちらが速いかを確認するための実験です。

実行のためにはMailCore.frameworkをビルドして、~/Library/Frameworksに入れておく必要があります。

だいたい同じぐらいの属性値を取り出してみたところ、MacBook Pro Retina 2012モデル(Core i7 2.66GHz)でmailcore2経由の処理のほうが1.8倍ぐらい高速(10回実行時の平均値)なことがわかりました。

漫然とAppleScriptからMailの属性値を取ると0.011秒、mailcore2経由だと0.006秒でした。1通のメールでこのぐらいなので、数十、数百通と処理を行うと差が開く可能性はあります。

ただし、普通にMail.appからメールの属性値を取り出す場合にはpropertiesでまとめて取得するのが賢いやりかたなので、そこまで露骨に処理速度の差は出ないかもしれません。

それでも、mailcore2でしか取得できない情報が割といろいろあるので、mailcore2を使っての処理も悪くない感じです(意外でした)。Mailのメッセージのソースをmailcore2で処理できるかどうかの実験だったのですが、速度もなかなか速かったので速度比較をしてみたものです。

AppleScript名:Mail.appで選択中のメッセージからソースを取得してMailCoreで再組み立てして解釈
– Created 2017-01-23 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “MailCore” –https://github.com/MailCore/mailcore2
–http://piyocast.com/as/archives/4406

tell application “Mail”
  set a to selection
  
if a = {} then error “No Selection”
  
set aa to first item of a
  
set aSource to source of aa –メールのソースを取得
end tell

set aStr to current application’s NSString’s stringWithString:aSource
set aData to aStr’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)

set aHeader to current application’s MCOMessageHeader’s headerWithData:aData
set aT1 to (aHeader’s subject()) as string
–> “attachment test”
set aT2 to (aHeader’s bcc())
–>  missing value
set aT3 to (aHeader’s cc())
–>  missing value
set aT4 to (aHeader’s |date|()) as date
–>  date “2017年1月20日金曜日 16:07:14″
set aT5 to (aHeader’s |from|())
–>  (MCOAddress) mailcore::Address:0×600000637ee0 Takaaki Naganoya
set aT6 to (aHeader’s inReplyTo())
–>  missing value
set aT7 to (aHeader’s receivedDate())
–>  missing value
set aT8 to (aHeader’s |references|())
–>  missing value
set aT9 to (aHeader’s replyTo())
–>  missing value
set aT10 to (aHeader’s sender())
–>  missing value
set aT11 to (aHeader’s |to|())
–>  (NSArray) {(MCOAddress) mailcore::Address:0×618000a37460 長野谷隆昌 }
set aT12 to (aHeader’s userAgent()) as string
–>  ”Apple Mail (2.3259)”
set aT13 to (aHeader’s allExtraHeadersNames()) as list
–>  {”Return-Path”, “Content-Type”, “Delivered-To”, “X-Virus-Status”, “X-Mailer”, “Received”, “Mime-Version”}
set aT14 to (aHeader’s extraHeaderValueForName:“X-Mailer”) as string
–>  ”Apple Mail (2.3259)”
set anAddress to (aHeader’s |from|())
–>  (MCOAddress) mailcore::Address:0×6180006393c0 Takaaki Naganoya
set anAdrName to (anAddress’s displayName()) as string
–>  ”Takaaki Naganoya”
set anAdrName to (anAddress’s mailbox()) as string
–>  ”maro_ml@piyocast.com”

★Click Here to Open This Script 

AppleScript名:Mail.appで選択中のメッセージから各種属性値を取得する
– Created 2017-01-23 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4406

tell application “Mail”
  set a to selection
  
if a = {} then error “No Selection”
  
set aa to first item of a
  
  
set aSub to subject of aa
  
set aBCC to bcc recipient of aa
  
set aCC to cc recipient of aa
  
set aRecL to to recipient of aa
  
set aRep to reply to of aa
  
set aRecD to date received of aa
  
set aSenD to date sent of aa
  
set aSender to sender of aa
  
log aSender
  
–User AgentはHeaderから自力で取得
  
set aHead to all headers of aa
  
–displayNameはsenderから文字列処理で自力で
  
–mailboxはsenderから文字列処理で自力 or
end tell

★Click Here to Open This Script 

2017/01/20 MailCore2でメールのeml形式ファイルから添付ファイルを抽出

オープンソースのフレームワーク「MailCore2」を使ってeml形式のメールファイルを読み込んで添付ファイルを取り出すAppleScriptです。

実行のためにはMailCore.frameworkをビルドして、~/Library/Frameworksに入れておく必要があります。

普通にMail.appをGUIなりAppleScriptから操作すれば、もっと手軽にメールの添付ファイルは取得できるわけですが、本Scriptは「うっかり書き出してしまったemlファイル」からの添付ファイル(Zip圧縮したファイルのみ)の抽出を行います。

macOSのMail.appから「添付ファイルつきのメッセージ」をFinderにドラッグ&ドロップして作成したeml形式のファイルが処理対象です。

この処理対象ファイルを本AppleScriptで処理すると、デスクトップフォルダに添付ファイルが保存されます。

MIMEがマルチパートであることは認識していましたが、入れ子状態の階層が割と多い、多階層の入れ子にできるようなので、本来であれば再帰処理すべきなのかもしれません。また、Mail.app以外のメーラーから来たメールはMIMEの組み立て方が異なっているかもしれません。あくまで、macOS 10.12上のMail.app v10.2同士でやりとりした添付ファイルつきメールの処理が本Scriptで行えた、ということにすぎません。

AppleScript名:MailCore2でメールのeml形式ファイルから添付ファイルを抽出
– Created 2017-01-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “MailCore” –https://github.com/MailCore/mailcore2
—http://piyocast.com/as/archives/4399

set aPath to POSIX path of (choose file of type {“com.apple.mail.email”})

set fileContents to current application’s NSData’s dataWithContentsOfFile:aPath options:(current application’s NSDataReadingMappedIfSafe) |error|:(missing value)
if fileContents = missing value then return

set aParser to current application’s MCOMessageParser’s messageParserWithData:fileContents

set aBodySet to aParser’s mainPart()
set pList to aBodySet’s parts()
set pCount to pList’s |count|()
log pCount
–> 2

set aDtPath to POSIX path of (path to desktop)

–本来は再帰で処理すべき?
repeat with i in (pList as list)
  set aMimeType to (i’s mimeType()) as string
  
–> “text/plain”
  
  
set aCharset to (i’s charset()) as string
  
–> “UTF-8″
  
  
if aMimeType is in {“text/plain”, “text/html”} then
    set aStr to i’s decodedString()
    
  else if aMimeType = “application/zip” then
    set aData to i’s |data|()
    
set aFileName to (i’s filename()) as string
    
set fRes to writeDataToPath(aDtPath, aFileName, aData) of me
    
log fRes
    
  else
    –MimeTypeとcharsetがmissing valueのpart(たぶん、Attachment)
    
set ppList to i’s parts()
    
set ppCount to ppList’s |count|()
    
    
repeat with ii in (ppList as list)
      set bMimeType to (ii’s mimeType()) as string
      
set bCharset to (ii’s charset()) as string
      
      
if bMimeType is in {“text/plain”, “text/html”} then
        set aStr to ii’s decodedString()
        
      else if bMimeType = “application/zip” then
        set bData to ii’s |data|()
        
set bFileName to (ii’s filename()) as string
        
log bFileName
        
set fRes to writeDataToPath(aDtPath, bFileName, bData) of me
        
log fRes
      end if
    end repeat
    
  end if
  
end repeat

–NSDataをファイル書き込み。パス(aPath)はPOSIX pathで与える
on writeDataToPath(aPath, aName, aNSData)
  set newPath to aPath & aName
  
set aRes to aNSData’s writeToFile:newPath atomically:true
  
return aRes as boolean
end writeDataToPath

★Click Here to Open This Script 

2017/01/18 MailCore2でメールのeml形式ファイルを読み込む v2

オープンソースのフレームワーク「MailCore2」を使ってeml形式のメールファイルを読み込んでテキスト化するAppleScriptです。

実行のためにはMailCore.frameworkをビルドして、~/Library/Frameworksに入れておく必要があります。

本来、Mail.appでメールから本文テキストを取得するのは簡単で、小学生レベルの処理内容ですが本AppleScriptは、Mail.appから書き出されたemlファイル(Mail.appからドラッグ&ドロップで単体のメールを書き出したファイル)からの本文抽出を行います。

mail_eml.png

AppleScriptでなんともならない書類の筆頭であった「.eml」形式ファイルを読み込んでプレーンテキスト化できるようになったことには、大きな意義があるような気がします。

AppleScript名:MailCore2でメールのeml形式ファイルを読み込む v2
– Created 2017-01-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “MailCore” –https://github.com/MailCore/mailcore2
—http://piyocast.com/as/archives/4397

set aPath to POSIX path of (choose file of type {“com.apple.mail.email”})

set fileContents to current application’s NSData’s dataWithContentsOfFile:aPath options:(current application’s NSDataReadingMappedIfSafe) |error|:(missing value)
if fileContents = missing value then return

set aParser to current application’s MCOMessageParser’s messageParserWithData:fileContents

–改行を削除してメール本文をプレーンテキスト化
set aBody1 to (aParser’s plainTextBodyRendering()) as string
–>  ”技術書典 事務局です。 この度は技術書典2へのサークル参加申し込み、誠にありがとうございました。 ◎貴サークル「Piyomaru Software」は、 え-11 に配置されました。…

–改行を維持しつつメール本文をプレーンテキスト化
set aBody2 to (aParser’s plainTextBodyRenderingAndStripWhitespace:false) as string
(*
–>  ”技術書典 事務局です。
この度は技術書典2へのサークル参加申し込み、誠にありがとうございました。
◎貴サークル「Piyomaru Software」は、 え-11 に配置されました。
*)

★Click Here to Open This Script 

2016/11/08 SierraのMail.app v10.2でSignatureにバグ

macOS Sierra(10.12)搭載のMail.app v10.2でsignatureの署名の名前(name)も署名本文テキスト(content)にもアクセスできないというバグがあることが判明しました。properties ofでアクセスしてこれらの属性値をまとめて取得しようとしても、おかしな結果が返ってきてしまいます。

AppleScript名:SierraのMail.app v10.2でSignatureにバグ
–http://piyocast.com/as/archives/4307
tell application “Mail”
  set aList to name of every signature
  
–> {missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value}
  
  
set bList to content of every signature
  
–> {missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value}
  
  
set cList to properties of every signature
  
–> {{class:item}, {class:item}, {class:item}, {class:item}, {class:item}, {class:item}, {class:item}, {class:item}, {class:item}, {class:item}, {class:item}, {class:item}, {class:item}, {class:item}, {class:item}, {class:item}}
end tell

★Click Here to Open This Script 

2016/10/12 うっかりミス例:バージョン確認

macOS SierraになってMail.appのバージョンも”10.1″になりました。Mail.app用に作って毎日便利に使っている、

「選択中のメールフォルダ以下のメールを仕分けする。各サブフォルダについている名称をカンマで分離して同義語を許容。さらに、フォルダ名の長い順に重視してSubjectとメールフォルダ名のマッチングを行う」

という超高機能AppleScriptが、macOS Sierraになって正常に動かなくなっていました(スゲー困る)。この原因がわかったので、そのあたりを説明します。

原因は、バージョン番号の判定をしくじっていたというものでした。

バージョン番号は文字列で返ってくるため、macOS SierraのMail.appだと、

AppleScript名:バージョンを求める0
tell application “Mail”
  set aVer to version
end tell
–> “10.1″

★Click Here to Open This Script 

のように”10.1″とかえってきます。

Mail.appは、OS X 10.8あたりで(AppleScriptのmove命令の)機能がダウンして「複数のmessageを他のフォルダに一発で移動させる」ことができなくなりました。

解決策もないため、仕方なくMail.appのバージョン番号を見て「6よりも新しいバージョンであれば1 messageずつループして移動させる」ように処理していました。

ここのバージョン番号の比較判定で「considering numeric strings」を指定していなかったので、「10.1」という文字列を「6より大きくない」と判定。昔のバージョンどおり、複数messageを同時に移動させようとして失敗していたのでした。

大昔に書いて、小幅な改良を施しつつ使い続けているAppleScriptの場合には、こういう「うっかりミス」がOSバージョンアップにともなって表面化することもあります。ご注意ください。

ちなみに、このMailの仕分けScriptの場合、最初に作ったのは2005年ごろのようで、当時はEntourageを相手にしていました。Entourageのデータベースの自己破壊が激しくなり、とても常用できなくなったのをきっかけにMail.appに全面移行して支援ツール類もすべてMail.app用に書き換え。その後、二度とMicrosoftのメーラーは使わなくなりました。

Scriptに残されている最古のコメントが以下のものです。

「Entourageで、指定フォルダのメッセージを再仕分け1.13」
2005年 5月 30日 月曜日 7:48:16 PMにバージョンアップ

Entourageで選択中のフォルダ内にあるメールを、そのフォルダ内のサブフォルダにフォルダ名とサブジェクトの比較を行って再仕分けを行うAppleScript。

短い単語の振り分けが厳しすぎるので緩和
Growlがあれば、それを用いるように機能追加

振り分けずみのメールをスキップする機能を付けたバージョン。スキップ機構を単純化したことにより、速度低下を防いだ。

フォルダ名称の長さでソートして、長い順に仕分けを行う仕様
ハイフンも空白もピリオドも大文字小文字も無視して比較

AppleScript名:バージョンを求める1
tell application “Mail”
  set aVer to version
  
if aVer > “6″ then
    display dialog “Newer”
  else
    display dialog “Older”
  end if
end tell

★Click Here to Open This Script 

mailver1.jpg
▲macOS SierraのMail.appに対してバージョン番号を求め、漫然と大小判定した結果。想定していたものと異なる結果になってしまった

AppleScript名:バージョンを求める2
tell application “Mail”
  set aVer to version
  
considering numeric strings
    if aVer > “6″ then
      display dialog “Newer”
    else
      display dialog “Older”
    end if
  end considering
end tell

★Click Here to Open This Script 

mailver2.jpg
▲considering numeric strings節で囲って、バージョン文字列の判定をきちんと行った結果、期待どおりの処理結果が得られた

2016/06/06 Mail.appで複数のメッセージを移動させる

Apple純正のメーラーアプリケーション「Mail.app」にはmove命令があり、message(メール)を指定の(Mail.app上の)フォルダに移動させることが可能です(ファイルシステム上のフォルダではありません)。

1つのmessageを移動させる場合には問題ないのですが、複数のmessageを同時に移動させる場合にはエラーになります。

この挙動がおかしくなったと感じたのは、OS X 10.8だったと記憶しています。複数のmessageをリストに入れ、move命令で一気に移動させる処理でいきなりエラーが出るようになりました

複数のmessageを一度にmoveできると、アプリケーション側との通信頻度を下げられ、処理速度の面で大幅に有利になるため、対応してほしいところです。

Mail.appのAppleScript用語辞書にもmove命令の説明で、object(s) to move を指定できるという表記があり、

mailappdic.png

複数のメールを一度に移動できることを期待したいところです。

しかし、今日にいたってもリストに入れた複数のmessageは移動できず、にもかかわらずAppleScript用語辞書にはobject(s)と複数形で記載され続けるという状況が続いています。

そこで、自分が期待するところの「複数のmessage」と、Appleが定義するところの「複数のmessage」が実は異なるのではないか、と疑うようになりました。

 自分の定義:リスト型変数に入れた複数のmessage
 Appleの定義:上記以外の何か???

まず、現時点で動作する安全な表記を確認するとこのリスト(↓)のようになります。複数のmessageをリストに抽出し、ループで1つずつmoveします。

AppleScript名:受信フォルダ内の特定のメールアドレスから来たメールを別のフォルダに順次移動
tell application “Mail”
  tell inbox
    set mList to every message whose sender contains “notify@twitter.com”
  end tell
  
  repeat with i in mList
    set j to contents of i
    
ignoring application responses
      move j to mailbox “メルマガ/_個人的なメール/twitter”
    end ignoring
  end repeat
end tell

★Click Here to Open This Script 

ここで、フィルタ参照で取得したmessageのリストに対して直接move命令を実行するとエラーになります。

AppleScript名:受信フォルダ内の特定のメールアドレスから来たメールを別のフォルダに一括移動(動かないパターン)
tell application “Mail”
  set aList to (every message in inbox whose sender contains “notify@twitter.com”)
  
move aList to mailbox “メルマガ/_個人的なメール/twitter” –Error
end tell

★Click Here to Open This Script 

そこで、「リストに入れない状態で、しかも複数のmessageを与えてみたらどうなるだろう?」と考え、実際に書いて試してみました。

AppleScript名:受信フォルダ内の特定のメールアドレスから来たメールを別のフォルダに一括移動
tell application “Mail”
  move (every message in inbox whose sender contains “notify@twitter.com”) to mailbox “メルマガ/_個人的なメール/twitter”
end tell

★Click Here to Open This Script 

あれ? 一括移動できた(^ー^;;; しかし、リストに入れたりソートしたりユニーク化したものを渡せないと、ちょっと使い勝手がよくありません。

しばし悩んだものの、冗談半分で、

AppleScript名:受信フォルダ内の特定のメールアドレスから来たメールを別のフォルダに一括移動(動かないパターン) の解決
tell application “Mail”
  set aList to a reference to (every message in inbox whose sender contains “notify@twitter.com”)
  
move aList to mailbox “メルマガ/_個人的なメール/twitter” –OK
end tell

★Click Here to Open This Script 

と、a reference toで参照したものをリストに入れてみたところ、希望の動作を行いました(!!!!!)。

ただ、このリストを加工したりできないので、問題はあまり解決していないような、、、、

2015/05/13 Mailで有効なmailアカウントの新規メール取得を強制的に有効にする

Mail.appに設定しているmailアカウントのうち、有効なもの(使用停止にしていないもの)の新規メール取得状況を強制的に「取得する」状態に設定するAppleScriptです。

何も、初期状態に戻さなくてもいいケースもあるのでは?(Mac miniの最低ランクのマシンにAppleScriptを稼働させて専用機化するような場合)と考えて、少し機能の異なるものも作っておいた次第です。

AppleScript名:Mailで有効なmailアカウントの新規メール取得を強制的に有効にする
forceRecoverEveryMailReadSchedule() of me

on forceRecoverEveryMailReadSchedule()
  tell application id "com.apple.mail"
    set acList to every account whose enabled is true –有効なMailアカウントだけを取得
    
repeat with i in acList
      set j to contents of i
      
set include when getting new mail of j to true
    end repeat
  end tell
end forceRecoverEveryMailReadSchedule

★Click Here to Open This Script 

2015/05/13 Mailで有効なmailアカウントの新規メール取得を元に戻す

Mail.appに設定しているmailアカウントのうち、有効なもの(使用停止にしていないもの)の新規メール取得状況を(あらかじめバックアップしておいた)元の状態に戻すAppleScriptです。指定した状態にできたかどうかをbooleanで(true/false)返します。

「Mailで有効なmailアカウントの新規メール取得を停止して元の設定状態を返す」AppleScriptを実行してなにがしかのまとまった処理をしたあとで、後処理に実行する種類のものです。

AppleScript名:Mailで有効なmailアカウントの新規メール取得を元に戻す
set origList to {true, true, true, true}
set aRes to recoverEveryMailReadSchedule(origList) of me
–> true

on recoverEveryMailReadSchedule(origList)
  set aList to {}
  
  
tell application id "com.apple.mail"
    set acList to every account whose enabled is true –有効なMailアカウントだけを取得
    
set aCount to 1
    
    
repeat with i in acList
      set j to contents of i
      
set jj to contents of item aCount of origList
      
      
set include when getting new mail of j to jj
      
set the end of aList to include when getting new mail of j
      
set aCount to aCount + 1
    end repeat
  end tell
  
  
return (aList = origList) –設定が成功したかどうかをBooleanで返す
  
end recoverEveryMailReadSchedule

★Click Here to Open This Script 

2015/05/13 Mailで有効なmailアカウントの新規メール取得を停止して元の設定状態を返す

Mail.appに設定しているmailアカウントのうち、有効なもの(使用停止にしていないもの)の新規メール取得を停止し、各mailアカウントのメール取得状態をリストで返すAppleScriptです。

Mail.appで受信したメール(Inboxに入っているメール)に対してなにがしかの処理を行いたいときに、まず最初に「後続の新着メールが発生しないように、メール受信を一時的に止める」ことが必要になってきます。

ただし、最近のMail.appではメールチェックのスケジュール自体はいじくれないので、各mailアカウントのプロパティで「include when getting new mail」というものがあるので、これをfalseに設定してあげると新着メールの確認時にチェック対象から外れます(GUI側とも連動している)。

mail10.png

そして、元の状態がどうであったかを取得して、返り値として返します。

AppleScript名:Mailで有効なmailアカウントの新規メール取得を停止して元の設定状態を返す
set origList to stopEveryMailReadSchedule()
–> {true, true, true, true}

on stopEveryMailReadSchedule()
  set aList to {}
  
  
tell application id “com.apple.mail”
    set acList to every account whose enabled is true –有効な(enabled=trueな)Mailアカウントだけを取得
    
    
repeat with i in acList
      set j to contents of i
      
set the end of aList to include when getting new mail of j
      
set include when getting new mail of j to false
    end repeat
    
    
return aList –元の設定状態を取得して返す
    
  end tell
end stopEveryMailReadSchedule

★Click Here to Open This Script 

2015/05/11 Mailで選択中のMessageの添付ファイルをデスクトップに保存

Mail.appで選択中のMessageの添付ファイルをデスクトップに保存するAppleScriptです。

添付ファイルの単独保存については、いろいろBad Know-Howなやり方が(Mail.appのplistを読んで保存場所を求めて、そこから探すとか)存在していましたが、昔使ったものを使おうとしたらOS X 10.10では動きませんでした。

そこで、Mail.appのAppleScript用語辞書を眺めていたところ、添付ファイル(mail attachment)がsaveコマンドに応答すると書いてあったので、半信半疑で書いてみたらあっけなく動きました、、、

mail_attachment.png

AppleScript用語辞書を読まずには(対象アプリケーションをコントロールする)AppleScriptは書けない、基礎的な話なので・・・用語辞書のチェックは必須です。

本Scirptは、定期的にメールボックスをチェックして、PDF添付の特定の送信元のメールの添付書類を別途保存し、PDFをファイル変換してファイルサーバーにアップロードするような、放置状態で動作するAppleScriptのアプリケーションロボットを作成するために書いたものです。

AppleScript名:Mailで選択中のMessageの添付ファイルをデスクトップに保存
–Desktop FolderへのPathを求める
set aDtPath to (path to desktop folder) as string

–選択中のメッセージを求める
tell application “Mail”
  set aSel to selection
end tell

–選択中メールでループ、各メールに添付ファイルがあればDesktopに保存
tell application “Mail”
  repeat with i in aSel
    set j to contents of i
    
set attS to mail attachment of j
    
    
–messageに対する添付書類(mail attachment)でループ(1通のメールに複数添付の場合に対応)
    
repeat with ii in attS
      set jj to contents of ii
      
      
set aName to name of jj
      
set savePath to aDtPath & aName
      
      
–指定パスに添付ファイルを保存
      
save jj in file savePath
      
    end repeat
    
  end repeat
end tell

★Click Here to Open This Script 

2012/12/16 Mail.app上で選択したメールの発信元に応じてメール一覧の背景色を変える v2

同じメールアドレスの持ち主にメールではなく電話で連絡を取ろうとして、会社に電話をしたところ……相手は自宅からメールを出していたので、自宅に連絡し直す必要があった……というケースは、往々にしてあり得ることです。

そこで、メールの経由サーバーの違いをメールヘッダーから検出し、職場以外の場所(と思われる場所)からメールが送信された場合に、Mail.appのメール一覧の背景に色を付けて区分けしようとするAppleScriptを書いてみました。

mail1.png

電子メールのメールヘッダーをすべて表示させ、「Recieved:」ヘッダーを調べてみると……メールの伝送経路が変われば、その内容が変わるわけで、相手が職場「以外の場所」から送信した場合には変わります。その「違い」を調べておいてプログラム中に直接書いてあります(これは、相手の環境によって異なるため、プログラム内に書く検出用のサーバー名は書き換える必要があります)。

本Scriptは、Mail.app上でメールを選んでおいて実行すると……メールヘッダの「Recieved:」を調べて指定したメールサーバー名が入っている場合には件名の色を変更します。

本来、メール受信時に実行する「ルール」で「AppleScriptを実行」のアクションで実行したかったのですが………OS X 10.8.2上のMail.app v6.2ではこの「AppleScriptを実行」アクションにバグがあって、任意のAppleScriptを実行できません。早いところ直してほしいところです。

スクリプト名:Mail.app上で選択したメールの発信元に応じてメール一覧の背景色を変える v2
script spd
  property aHead : missing value
  
property hList : {}
end script

tell application “Mail”
  set aSel to selection
  
if aSel = {} or aSel = “” then
    display dialog “何もメールが選択されていません” buttons {“OK”} default button 1 with icon 2
    
return
  end if
  
set aMes to contents of first item of aSel
end tell

procAMailBGColorBySnetNetworkLocation(aMes) of me

–指定メールの発信元のネットワークに応じてメール一覧の背景色を変更する
on procAMailBGColorBySnetNetworkLocation(aMes)
  tell application “Mail”
    –選択したメール(1通)のメールヘッダーをすべて取得する  
    
set aHead of spd to all headers of aMes
    
    
–メールヘッダーをなめてみる
    
set hList of spd to paragraphs of aHead of spd
    
    
repeat with i in hList of spd
      set j to contents of i
      
      
if j begins with “Received:” then
        if j contains “.flets.hi-ho.ne.jp” then
          
          
–自宅の固定回線の場合
          
set background color of aMes to green –グリーン
          
return
          
        else if j contains “.emobile.ad.jp” then
          
          
–Emobile経由(移動中)の場合
          
set background color of aMes to yellow –イエロー
          
return
          
        end if
      end if
    end repeat
    
  end tell
end procAMailBGColorBySnetNetworkLocation

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2012/10/27 OS X v10.8.2 追加アップデート 1.0がMail.appのAppleScript系のバグを修正

「OS X v10.8.2 追加アップデート 1.0」は非常に変則的なOSのアップデートでしたが、Mac OS X 10.6以来ながらく発生していたMail.appのバグを修正するものでした。

Mac OS X 10.6以降、AppleScriptからMail.app上でフォルダを作成すると、一番末尾にフォルダが並んでしまうというバグです。GUI側から作成したフォルダはABC順に並ぶのですが、AppleScript側から作成するとまともにソートされず、既存のフォルダの後に追加される格好になっていました。

これが、OS X v10.8.2 追加アップデート 1.0によって修正され、長らく悩まされていたMail.appのバグが直ったのでした。

ただ、急に直るということは……逆に、バグが復活する可能性もあるわけで、アップデートのたびに確認すべき項目であるともいえます。もちろん、リリース前にAppleのエンジニア自身が確認すべきことは言うまでもありません。

2012/09/30 Mailで選択中のmessageの親フォルダのフルパスを文字で取得する

OS X 10.8標準装備のMail.app v6で、選択中のメッセージに対して、親フォルダのフルパスを文字で取得するAppleScript+動作確認用の呼び出し側Scriptです。

動作確認用に、「メール」アプリ上で選択中のメッセージが入っているフォルダのフルパスを取得し、そのフォルダ中に指定文字列を含むフォルダが存在するかどうかを確認するAppleScriptを書いてあります。ただし、あくまで動作確認用であり、本体部分は、

–与えられたmailboxのフルパスをテキストで返す
on getFullPath(mBox)

および、

–親フォルダを取得
on getParent(aMailBox)

の2つのサブルーチンです。getFullPathは10.8およびそれ以前のMac OS X(10.4あたりまで)に対応していますが、getParentは10.8にしか対応していませんね。本来、getParentもバージョン判定を行う必要があります。

mail_folder.png

スクリプト名:Mailで選択中のmessageの親フォルダのフルパスを文字で取得する
tell application “Mail”
  –先にSelectionを取得してみる
  
set aSelection to selection
  
if aSelection = {} then
    display dialog “Mail.app上でメールが選択されていません。” buttons {“OK”} default button 1 with icon note with title “ERROR”
    
return
  end if
  
  
–選択中のメールボックスを取得
  
tell message viewer 1
    set mbList to selected mailboxes
  end tell
  
  
–Selectionから情報を取得する処理
  
set anItem to item 1 of aSelection
  
set anItemProp to properties of anItem
  
set aStorage to mailbox of anItemProp
  
set aSubject to subject of anItemProp
  
  
  
set aRes to text returned of (display dialog “存在確認するフォルダ名称は?” default answer aSubject)
  
  
–すでに同一名称でフォルダが作成されていないか確認
  
tell aStorage
    ignoring case, diacriticals, hyphens, punctuation and white space
      set fList to every mailbox whose name contains aRes
    end ignoring
  end tell
  
  
set tmpFolObj to first item of fList
  
set tmpRes to getFullPath(tmpFolObj) of me
  
  
return tmpRes
  
end tell

–与えられたmailboxのフルパスをテキストで返す
on getFullPath(mBox)
  tell application “Mail”
    set aVer to version as number
    
    
set fullPath to name of mBox
    
    
repeat
      set mBox to getParent(mBox) of me
      
      
try
        set aClass to class of mBox
      on error
        exit repeat
      end try
      
      
if aVer 6 then
        –Mountain Lion搭載のMail 6.0以降の場合
        
if aClass is not equal to container then – ここを変更
          exit repeat
        end if
      else
        –それ以前の場合?
        
if aClass is not equal to mailbox then – ここを変更
          exit repeat
        end if
      end if
      
      
set aName to name of mBox
      
set fullPath to aName & “/” & fullPath
    end repeat
  end tell
  
  
return fullPath
end getFullPath

–親フォルダを取得
on getParent(aMailBox)
  tell application “Mail”
    tell aMailBox
      try
        set a to properties
        
set b to container of a
      on error
        return {“”, “”}
      end try
    end tell
  end tell
  
return b
end getParent

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2012/09/30 Mail 4.0->6.0の移行でAppleScript関連機能の変更が発生

Mac OS X 10.7に対する海外のScripterの評判が散々だったこともあり、(メイン環境を10.7には移行せずに)個人的にはMac OS X 10.6.8を使い続けていました。サブマシン上で検証する程度。

OS X 10.8がリリースされると、さすがに変更点が増えてきたので、「移行しないこと」自体がリスクになると考え、さっそくすべての(移行可能な)環境を10.8に移行させました。

Mac OS X 10.6に標準装備されているMail.app v4.0から、OS X 10.8のMail.app v6.0に移行し、Mail.app用のうち重要なものの幾つかが動かなくなってしまいました。

これらは、AppleScript用語辞書の差分検出だけでは検出できないものであり、実際に環境を移行してはじめて確認できたものです。

機能変更点その1:move命令で一括で複数のmesssageを移動できない

Subjectに基づいてメールの仕分けを行うAppleScriptを運用し、膨大なメーリングリストの内容を効率的に整理・活用してきましたが、これはMail.appが一括で複数のmessage(AppleScript風に正確にいえば、リストに入れたmessage)を移動できる仕様になっていたために実用的な運用ができていたものでした。

これが、OS X 10.8搭載のMail.app v6(あるいはそれ以前から)では、move命令で移動可能なのは1つのmessageのみであり、移動にえらく時間がかかるようになってしまいました(倍ぐらいベンチマーク値の高いSSD搭載マシンに移行したものの、前より遅い)。このあたり、文句を言って直るレベルなのかはひたすら不明です。

機能変更点その2:メールのフォルダ作成時にオブジェクト階層を無視するように

Mail.app上でのメールの整理方法は人それぞれだと思います。

一切整理せずにキーワード検索で探す方法をAppleは提唱しているようですが、それだと「いつも検索しているキーワードが何か」を覚えておく必要がありますし、どのあたりにどのメールがあって……というおおざっぱな仕分けはできません。毎回、検索結果の中から自分で必要な情報にたどり着く必要があり、無駄な時間がかかります。

では自分はどうやって整理しているのか……といえば、ひたすらキーワードによるフォルダ(ただし、カンマで複数のキーワードを付けておく)分けを行うもので、ある程度フォルダ分けが進んでくると効率的に整理が行えます。ただし、同じやり方をすべての人に薦めるものではありません(辛抱強さと几帳面さがないとムリ)。

その整理を行うために、フォルダを細かく作って自動振り分けするようなAppleScriptを作り、運用しているものです。

前置きが長くなりましたが、この「Mail.app上でフォルダを作る」という作業は日常的におこなっているものであり、10.8に(Mail.app v6に)移行して最初に直面した問題でもありました。つまり、いままで作って便利に使ってきたScriptが動かなくて困った、と。

ただし、これには明確な対処方法があって……

 「tell文で指定した階層のフォルダに指定名称のフォルダを作る」

というやり方ではなく、

 「作成するフォルダをフルパス指定する」

というやり方に変えれば大丈夫です。このため、オブジェクトで指定したフォルダのフルパスを取得するサブルーチンの登場回数が増えつつあります。

2011/10/09 Mail.appで添付ファイルを指定してメール送信

Mail.appで指定のファイルを添付してメールを作成・送信するAppleScriptです。

★本Scriptを実行する際には、最初に送信先のアドレスを書き換えてからにしてください

Googleで「AppleScript Mail attachment」とキーワードを入れると(海外のサイトに掲載されているAppleScriptが)ザクザク出てくる程度の内容ではあるのですが、本Blogの過去の記事検索では出てこなかったので、掲載しておきます。

この基本的なサンプルをさらに書き換えると、

・choose fileなどというユーザーに場所を尋ねる(放置状態だと処理が止まってしまう)やりかたではなく、指定フォルダ中の指定ファイルを自動で指定
・添付ファイルの各種情報を取得して、その内容をメールの本文に反映させる
・所定の容量以上の場合には、添付しないでDropboxにアップロードしてそのURLをメール本文に添付して送信
・複数のファイルを添付指定(ループで)して送信

などのAppleScriptに発展させていけます。もちろん、サブルーチン化して使い回しのきく部品に仕立てると有用性はもっと上がります。

けっこうよく使う処理で……何か遠隔地で稼働しているMacのシステムからエラーを返す場合とか、必要な場合に画面のスナップショットをとって添付して送信してくるとか、シンプルではあるものの依然としてメールによるレポートが有用な手段であることに違いはありません。

Twitterで実行結果を知らせてくるとか、iChat経由でメッセージを送ってくるとか、Blogに新規記事を作成してレポートしてくるといった処理もAppleScriptで割と楽勝でできる昨今ですが、とりあえずMailで情報を送るやりかたは最低限マスターしておきたいものです。

スクリプト名:添付ファイルを指定してメール送信
set theName to “ぴよまるさん”
set theAddress to “maro@piyocast.com”
set theSubject to “メールの題名ですぴよ”
set theBody to “ぴよまるさんへ

メールにファイルを添付しましたよ〜。ぴよ〜。

ひよこさんより

set theAttachment to choose file with prompt “添付ファイルを選択してください”

tell application “Mail”
  set newMessage to make new outgoing message with properties {subject:theSubject, content:theBody & return & return}
  
tell newMessage
    set visible to false –サイレントでメール作成(メールのウィンドウを表示しない)
    
    
–受取人の指定
    
make new to recipient at end of to recipients with properties {name:theName, address:theAddress}
    
    
–添付ファイルの指定
    
tell content
      make new attachment with properties {file name:theAttachment} at after the last paragraph
    end tell
    
    
–メール送信
    
send
    
  end tell
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/08/21 特定の語句を含むMail.appのフォルダ(mailbox)を抽出してフルパスを文字列化

Mail.app上で特定のキーワードを含むフォルダを探し出して、そのパスを一覧表示するAppleScriptです。

Mail.app上で、フォルダを作ってメールの整理をしている場合に、ある特定のキーワードを含むフォルダがどこに存在しているかを検索したくなることがあります。しかし、Mail.appにそういう機能は存在していません。

acs0.jpg

なければ作るまでで……AppleScriptで作り出して、フルパス表示用に作っておいたサンプルと合わせて所要時間5分ぐらいでしょうか。

Mail.appではフォルダ(mailbox)をフィルタ参照で抽出できるので、思いっきり楽でした。自分のメイン環境ではフォルダが1万6000個ぐらい存在(自動で作成させているので)しているのですが、個数のカウントも1秒かからない程度(MacBook Pro 2010 Core i7 2.66GHz)でした。

実際、本Scriptでもフォルダ(mailbox)のフィルタ参照による抽出はすぐに終わるのですが、フルパスをテキスト化するのに処理時間のほとんどの時間がかかっています。

acs1.jpg

acs2.jpg

本Scriptを早急に作る必要が出てきたのは……メールの整理中に間違えて「Accessibility Dev」MLのフォルダを捕まえてどこかにドロップしてしまって、フォルダが多すぎてどこに落としたか分からなくなってしまったためです。マウスを使っている場合には起こらない悲劇、、、

スクリプト名:特定の語句を含むMail.appのフォルダ(mailbox)を抽出してフルパスを文字列化
set searchKeyword to “AppleScript”

tell application “Mail”
  –特定キーワードを名前に含むフォルダ(mailbox)を抽出
  
set allPath to every mailbox whose name contains searchKeyword
  
  
–与えられたフォルダ
  
set bList to {}
  
repeat with i in allPath
    set the end of bList to getFullPath(i) of me
  end repeat
  
  
–結果の一覧表示
  
choose from list bList with prompt “検索結果:”
  
end tell

–与えられたmailboxのフルパスをテキストで返す
on getFullPath(mBox)
  tell application “Mail”
    set fullPath to name of mBox
    
    
repeat
      set mBox to getParent(mBox) of me
      
      
try
        set aClass to class of mBox
      on error
        exit repeat
      end try
      
      
if aClass is not equal to mailbox then
        exit repeat
      end if
      
      
set aName to name of mBox
      
set fullPath to aName & “/” & fullPath
    end repeat
  end tell
  
  
return fullPath
end getFullPath

–親フォルダを取得
on getParent(aMailBox)
  tell application “Mail”
    tell aMailBox
      try
        set a to properties
        
set b to container of a
      on error
        return {“”, “”}
      end try
    end tell
  end tell
  
return b
end getParent

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/06/15 Mail.appで指定のメールアカウントのみイネーブルに

Mail.appで複数のメールアカウントのみイネーブルにするAppleScriptです。

Mail.appに複数のメールアカウントを登録していて、職場や自宅などでメールアカウントの切り替えを行いたいような場合に使用します。

イネーブルにする対象は、Mail.appのメニューから「環境設定」で表示される環境設定ウィンドウの中の、「アカウント」で表示されるメールアカウントです。

mail_acc.jpg

Mail.appで場所に応じてメールアカウントの制御をしなくてはならず、最初は「送受信スケジュール」から当該のメールアカウントを外してみたのですが……恐ろしいことに、オフにしたはずのメールボックスへの送受信が行われたりしていました。そこで、メールアカウントそのもののオン/オフ制御を行う必要がある、と考えた次第です。

スクリプトメニューに入れて呼び出すと便利です。

mail1.jpg

スクリプト名:Mail.appで指定のメールアカウントのみイネーブルに
set eList to {“職場”, “Gmail”}

tell application “Mail”
  set enabled of every account to false
  
repeat with i in eList
    set j to contents of i
    
tell account j
      set enabled to true
    end tell
  end repeat
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

ちなみに、すべてのメールアカウントをイネーブルにする場合には、このように記述します。

スクリプト名:Mail.appですべてのアカウントをイネーブルに
tell application “Mail”
  set enabled of every account to true
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/04/05 Mail.appでメールの送信(プレーンテキストへの変換つき)

Mail.appでメールの送信を行うAppleScriptの、Mac OS X 10.6用に機能追加を行ったものです。

Mac OS X 10.6からは、AppleScript経由でMail.appをコントロールしてメールを作成・送信すると、なんとプレーンテキスト(=標準テキスト)ではなく、リッチテキストで送られてしまいます。言われてみないと、なかなか気づきにくい箇所です(コメント欄でのご指摘ありがとうございます)。

ただ……Mail.appの環境設定をいじくっても、挙動に変化はありません。AppleScriptから送信命令を送ると、リッチテキストになってしまいます。

バグ……だと思うのですが、すでにMac OS X 10.6.x上で修正の見込みはなく、その場しのぎにGUI Scriptingでメニューからコマンドを叩き込んで、強制的にプレーンテキストに変換してから送信するようにしてみました。

Mac OS X 10.7に向けて、修正の要望を出しておく必要があります。ただ、Appleはあくまでも統計的にバグの処理を行うため……1人や2人が騒いだところで取りあいません。このバグが直ってほしいと思った方は、Appleに意見を送ってください。

スクリプト名:Mail.appでメールの送信(プレーンテキストへの変換つき)
set aSubject to "メールのサブジェクトです"
set theSender to "maro@sender.com" –送信者アドレス
set recipientAddr to "maro@reciever.jp" –受信者アドレス
set bodyText to "ひよこさんへ
こんにちは。ひよこさん。
ひよこクラブへのおさそいです。

ぴよ〜"

sendMail(aSubject, theSender, recipientAddr, bodyText) of me

–Mail.appでメール送信を行う
on sendMail(theSubject, theSender, recipientAddr, bodyText)
  tell application "Mail"
    set newMessage to make new outgoing message with properties {subject:theSubject, content:bodyText}
    
tell newMessage
      set visible to true
      
set sender to theSender
      
make new to recipient at end of to recipients with properties {address:recipientAddr}
      
      
makeAMessageToPlain() of me
      
      
send
    end tell
  end tell
end sendMail

–作成したメールがリッチテキストなら標準テキスト(プレーンテキスト)に直す
on makeAMessageToPlain()
  activate application "Mail"
  
  
tell application "System Events"
    tell process "Mail"
      –メニュー内容が「Mail.app」>「フォーマット」>「標準テキストにする」だったら現在リッチテキストだと判断し、コマンド実行
      
set aTitle to title of menu item 11 of menu 1 of menu bar item 8 of menu bar 1
      
      
if aTitle = "標準テキストにする" then
        –「標準テキストにする」をクリック
        
click menu item 11 of menu 1 of menu bar item 8 of menu bar 1
      end if
    end tell
  end tell
end makeAMessageToPlain

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/08 Mail.appで選択しておいたメッセージに返信してsubjectと本文を加える

Mail.app上で選択しておいたメッセージの返信メッセージをreplyコマンドで作成し、その返信メッセージのサブジェクトと本文を変更するAppleScriptです。

USのAppleScript Users MLに投稿があった質問に答えておいたものです。どうも、Mail.appの動作が遅いらしくて……AppleScriptがMail.app側の動作を待ち切れず、返信メッセージを作成し終わる前に次のステップに進んでしまうため、delayコマンドなしではエラーが出てしまっていました。

GUI上でだいたい現象は観察できていたので、delayコマンド(最小限でいいので待機時間は0.1秒)を入れて動作を確認できました。3箇所に入れているdelayコマンドのうち、たぶん最初のものだけが必要不可欠なもので、あとの2つは「おまじない」に近いものです。ウチのCore i7 2.66GHzのMacBook Proではそのように感じられました。もっと高速で大量にCPU Coreが乗っているMac Proでは状況が違うかもしれません。

AppleScriptの処理系自体は、世間で言われるほど遅くないため……アプリケーションの状態を取得したり命令を発行したりすると、(AppleScript側が)けっこう待たされる感じです。そのため、アプリケーションとの通信頻度を下げることで大幅なスピードアップを図ったり、AppleScriptだけで処理をすることで速度を稼いだりするというテクニックが存在します。

やや、Mail.app側のバグのようにも見えますが、AppleScriptチームがMail.appチームを説得するには相当時間がかかりそうなので、Apple側が社内で対応する前に自衛手段を講じておくというのが、ベストな対策といったところでしょうか。

スクリプト名:Mail.appで選択しておいたメッセージに返信してsubjectと本文を加える
tell application “Mail”
  set msg to selection –Mail.appでメッセージを選択状態にしておく
  
set msg to first item of msg
  
  
set replied_msg to reply msg with opening window –選択しておいたメールの返信メッセージを作成
  
delay 0.1
  
  
–返信メッセージに対して操作を加える。
  
tell replied_msg
    set subject to “replied message”
    
delay 0.1
    
    
set content to “this is a replied message”
    
delay 0.1
    
  end tell
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/12/14 選択中のMailのSubjectの変化を吸収するための試作

Mail.appで選択中のメールをもとに、同一スレッド内のSubjectの変化を吸収して、最低限の変化のみを検出するようにするための試作AppleScriptです。

目下、Mail.app上で選択中のメールをもとにスレッドの参照関係図をMindjet MindManager上にプロットするAppleScriptを開発・実戦投入しており、入り組んだメールのフローをビジュアライズできています。

mind1.jpg

海外のMLに対しては非常に有効に使えているのですが、日本のMLの運用方法が海外のものと異なる場合が多いため、日本語のMLの情報をプロットしようとすると、Subject変更点がうまく検出できず、1通ずつSubjectが変更されているものとして検出されていたりします。

これを防ぐために、日本国内のMLの特殊な運用がどこなのか考えてみたところ……すべてのケースでそうとはいえないものの、

・Subject内のMLの識別子にシリアル番号を入れており、この部分が1通1通変化する

という現象に対処してあげればよいということが分りました。日本語Subjectの末尾が化けるといったMLに遭遇したこともありましたが、さすがに最近はそういうこともなくなってきたようで……。

そこで、そうした日本国内MLのSubjectの特性に合わせてSubjectの変化を吸収するような処理を試作してみました。実際に、現在使っているプログラムに組み合わせて使ってみようと思います。

スクリプト名:選択中のMailのSubjectの変化を吸収するための試作
–選択中のMailのSubjectの変化を吸収するための試作
tell application "Mail"
  set aSel to selection
  
set sbjList to {}
  
repeat with i in aSel
    set the end of sbjList to subject of i
  end repeat
end tell
sbjList
–> (*[sampleml:00019] ○○の話 , [sampleml:00021] Re: ○○の話 , [sampleml:00020] Re: ○○の話 , [sampleml:00024] Re: ○○の話 *)

set newList to {}
repeat with i in sbjList
  set j to contents of i
  
if "[" is in j and "]" is in j then
    set j1 to offset of "]" in j
    
set j2 to text (j1 + 1) thru -1 of j
    
set j2 to repChar(j2, " Re: ", "") of me
    
set j2 to repChar(j2, " ", "") of me
    
set the end of newList to j2
  end if
end repeat
newList
–>{"○○の話", "○○の話", "○○の話", "○○の話"}

–文字置換ルーチン
on repChar(origText, targStr, repStr)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/10/01 Mail.appの指定メールボックス内に任意のメールボックスを新規作成 v2

Mail.appの指定メールボックス内に任意のメールボックスを新規作成するAppleScriptです。

Mail.appのメールボックス・フォルダは階層構造にすることができ、かなり自由にAppleScriptから制御できます。目下、各メーリングリストのメールはMail.appのルールで各フォルダに仕分けるようにしており……そのルール設定をAppleScriptから読み出して、US Appleの主催しているメーリングリストの各仕分けフォルダに、一括で「10.6,Snow Leopard」というフォルダを作成指示するAppleScriptを作りたいと思っていました(このScriptはすでに完成し、一括で全MLに同一名称のメールボックスを作成できるようになりました。いや、便利便利)。

まずはMail.appのメールボックス・オブジェクトからメールボックスのフルパスを取得するAppleScriptを作成し、その次の段階として本AppleScriptを作成した次第です。

スクリプト名:Mail.appの指定メールボックス内に任意のメールボックスを新規作成 v2
global aFullPath

set aFullPath to “”

set aNewFolName to “10.6,Snow Leopard”
tell
application “Mail”
  –mailboxオブジェクトを渡すのは、全メール振り分けルールからML用のもの(名称に「_ML」が入っている)
  
–を抽出して、それに対してすべて処理を行うことを考えているため。その際に入手できるのは
  
–該当するメールボックスのオブジェクト(のリスト)
  set
aMB to mailbox “ML/Apple US/ASに関係のあるもの/SyncService” –mailboxオブジェクトを作ってみた
end tell
makeAFolderIfNotExist(aNewFolName, aMB) of me


on
makeAFolderIfNotExist(aNewFolName, aFolder)
  –パラメータとして渡されたメールボックスオブジェクトからフルパスの階層を取得する
  
–make mailbox full-path text from Mail.app’s mailbox object
  set
aFullPath to “”
  
extraxctTextFullPathOfMBObject(aFolder) of me
  set
aNewFolFullPath to aFullPath & “/” & aNewFolName
  set
aFullPath to “”
  
  tell
application “Mail”
    –指定名称を「含む」フォルダが存在するかどうかチェック
    tell
aFolder
      set tmpFolList to name of every mailbox whose name contains aNewFolName
    end tell
    
    if
tmpFolList is equal to {} then
      try
        make new mailbox at beginning with properties {name:aNewFolFullPath}
      on error erM
        display dialog erM & return & “Error in making new mail folder by name: ” & aNewFolName
      end try
    end if
  end tell
end makeAFolderIfNotExist

–Mail.appのメールボックスオブジェクトを渡すと、テキストのフルパスに変換
on
extraxctTextFullPathOfMBObject(aPath)
  tell application “Mail”
    try
      set parentPath to container of aPath
    on error
      return
    end try
    
    set
meName to name of aPath
    if
aFullPath = “” then –1回目のみスラッシュを入れないで処理
      set aFullPath to meName
    else
      –通常処理はこちら
      set
aFullPath to meName & “/” & aFullPath
    end if
    
    
extraxctTextFullPathOfMBObject(parentPath) of me –再帰呼び出し
  end tell
end extraxctTextFullPathOfMBObject

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/09/26 Mail.appのメールボックスオブジェクトを渡すと、テキストのフルパスに変換 v1

Mail.appのmailboxオブジェクトを与えると、そのフォルダ階層のパスを「/」で区切ったテキストにして返すサブルーチンです。

mailfol.jpg

Mail.appのmailboxオブジェクトのプロパティには、名称や上位階層のmailboxオブジェクトの情報は入っているものの、現在の階層を示すフルパスの情報が入っていません。mailboxオブジェクトを生成する際に、フォルダ階層のテキストで指定することになるので、mailboxオブジェクトを相手にするのではなく、その元となるテキスト情報を相手にすれば「楽」に処理はできます。ただ、それだとあまり柔軟性に富んだ処理が行えません。

そこで、mailboxオブジェクトを渡すと、フルパスをテキスト化するAppleScriptを書いてみました。

そもそも、こんなルーチンが欲しいと思ったのは……Mac OS X 10.6が登場して、Appleの各MLフォルダ内に「10.6, Snow Leopard」(カンマで区切って名前を付けておくと、それらのどれかでヒットしたメールをフォルダに振り分けるAppleScriptを運用中)といったフォルダを一括で作成する必要が出てきたためで……ほぼすべてのUS Appleのデベロッパー系MLを購読しているため、それをすべて手作業で行うのは骨が折れます。また、すでに手でフォルダを作ってあるところに対しては作成しない、という処理も行わなくてはなりません。

スクリプト名:Mail.appのメールボックスオブジェクトを渡すと、テキストのフルパスに変換 v1
(*

Mail.appのmailboxオブジェクトはフルパスのプロパティを持っていないため、オブジェクトで渡されると、それがどのパスに存在
しているものなのか、処理するのが非常に面倒。

そこで、mailboxオブジェクトを渡すと、再帰でパスを求めるルーチンを作ってみた。
処理前にグローバル変数aFullPathをクリアしておく必要がある
ルート階層に達したときにエラートラップで判定を行うが、ここはもう少しスマートな書き方に変えたほうがいい

*)

global aFullPath

set aFullPath to “”
tell application “Mail”
  set aMB to properties of mailbox “ML/Apple US/ASに関係のあるもの/SyncService” –mailboxオブジェクトを作ってみた
end tell

extraxctTextFullPathOfMBObject(aMB) of me
aFullPath
–> “ML/Apple US/ASに関係のあるもの/SyncService”

–Mail.appのメールボックスオブジェクトを渡すと、テキストのフルパスに変換
on extraxctTextFullPathOfMBObject(aPath)
  tell application “Mail”
    try
      set parentPath to container of aPath
    on error
      return
    end try
    
    
set meName to name of aPath
    
if aFullPath = “” then –1回目のみスラッシュを入れないで処理
      set aFullPath to meName
    else
      –通常処理はこちら
      
set aFullPath to meName & “/” & aFullPath
    end if
    
    
extraxctTextFullPathOfMBObject(parentPath) of me –再帰呼び出し
  end tell
end extraxctTextFullPathOfMBObject

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/03/09 アプリケーションに命令を行う記述方法で最短のもの

ひどくなまりのつよい記述方法であり、可読性が著しく下がるため推奨はしないのですが、アプリケーションにこんな記法でも命令できるという(悪い)見本です。

スクリプト名:アプリケーションに命令を行う記述方法で最短のもの
application "Mail" activate

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/03/09 Mail.appに登録されている各MLのフォルダ直下にあるメールのうち昨日の0時0分以降に受信したものを個別に数える

Mail.appに登録されているメール振り分けルールのうち、ルール名に「ML」がついているルールの振り分け先フォルダを求め、各メールフォルダの直下に存在するメールのうち、前日の0:00以降に受信したメールの本数をすべてカウントします。

mail05.jpg

メール振り分けルールのうち、「ML」がついているものが、メーリングリスト関連(と仮定して処理)。

MLの投稿数をランキング表示するAppleScript StudioのGUIつきアプリを作った際の初期試作品です。

スクリプト名:Mail.appに登録されている各MLのフォルダ直下にあるメールのうち昨日の0時0分以降に受信したものを個別に数える
global mList, mList_r

set yesterdayDate to ((current date) - 1 * days)
set time of yesterdayDate to 0
set mList to {}
set mList_r to a reference to mList

set mlLocList to getMLRulesStorage() of me
tell application "Mail"
  repeat with i in mlLocList
    tell i
      set mCount to count (every message whose date received > yesterdayDate)
    end tell
    
if mCount > 0 then
      set the end of mList_r to {name of i as string, mCount}
    end if
  end repeat
end tell

set bList to shellSortListDecending(mList, 2) of me
bList

Mail.appのRuleのうち名称に「_ML」が入っているものの、保存先メールボックスを抽出
on getMLRulesStorage()
  tell application "Mail"
    set mbList to move message of every rule whose name contains "ML" and name of it does not contain "会社"
  end tell
  
return mbList
end getMLRulesStorage

シェルソートで入れ子のリストを昇順ソート
on shellSortListAscending(a, keyItem)
  set n to length of a
  
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
  
repeat with h in cols
    if (h (n - 1)) then
      repeat with i from h to (n - 1)
        set v to item (i + 1) of a
        
set j to i
        
repeat while (j h) and ((contents of item keyItem of item (j - h + 1) of a) > (item keyItem of v))
          set (item (j + 1) of a) to (item (j - h + 1) of a)
          
set j to j - h
        end repeat
        
set item (j + 1) of a to v
      end repeat
    end if
  end repeat
  
return a
end shellSortListAscending

シェルソートで入れ子のリストを降順ソート
on shellSortListDecending(a, keyItem)
  set n to length of a
  
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
  
repeat with h in cols
    if (h (n - 1)) then
      repeat with i from h to (n - 1)
        set v to item (i + 1) of a
        
set j to i
        
repeat while (j h) and ((contents of item keyItem of item (j - h + 1) of a) < (item keyItem of v))
          set (item (j + 1) of a) to (item (j - h + 1) of a)
          
set j to j - h
        end repeat
        
set item (j + 1) of a to v
      end repeat
    end if
  end repeat
  
return a
end shellSortListDecending

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/03/09 Mailで表示しているフォルダで送信日時が重複しているメールを削除v1

Mail.appで表示しているフォルダ中で送信日時(日付、時:分:秒)が重複しているメールを削除するAppleScriptです。

たとえば、たまたまメーリングリストに登録しているメールアドレスを他のものに変更する作業を行ったとして、たまたま2つのアドレスが重複して登録されている時間帯があって……同じメールを重複して受信してしまっているような時に、これを送信日時で検出して削除を行います。

すべて処理対象にすると処理対象が多すぎることが予想されたため、指定日時「以降」のメールのみを対象とするように絞り込みを行っています。

Mail.appでは複数のビューワーウィンドウを表示できるので、複数あった場合には最前面のビューワーウィンドウが対象となります。

mail01.jpg

こんな風にメールフォルダが階層構造になっていて……

mail02.jpg

最前面のビューワーで選択されているメールフォルダが対象で……

mail03.jpg

重複しているメールを……

mail04.jpg

すべて削除します。

スクリプト名:Mailで表示しているフォルダで送信日時が重複しているメールを削除v1

set yesterdayDate to "2009/3/1" 指定日時以降を対象とする
set yesterdayDate to date yesterdayDate

set aMailBox to getSelectedOneMailBox() of me
tell application "Mail"
  
  
tell aMailBox
    set mList to (every message whose date sent > yesterdayDate)
  end tell
  
  
set sList to {}
  
repeat with i in mList
    set the end of sList to date sent of i
  end repeat
  
  
  
set {itemList, ssList} to detectDuplicationSimple(sList) of me
  
  
repeat with i in itemList
    set anMessage to item i of mList
    
tell anMessage
      delete
    end tell
  end repeat
end tell

リスト中の重複検出
on detectDuplicationSimple(cList)
  copy cList to ccList
  
  
set j to length of ccList
  
set dupList to {}
  
set itemList to {}
  
  
repeat with i from 2 to j
    set first_item to item 1 of ccList
    
    
set ccList to rest of ccList
    
if first_item is in ccList then
      set the end of dupList to first_item
      
set the end of itemList to (i - 1)
    end if
  end repeat
  
  
return {itemList, dupList}
end detectDuplicationSimple

Message Viewerで現在表示中のメールボックスの情報を1つのみ返す
on getSelectedOneMailBox()
  tell application "Mail"
    tell message viewer 1
      set mbList to selected mailboxes
    end tell
  end tell
  
if length of mbList is equal to 0 then
    return ""
  end if
  
  
set aMailBox to contents of (item 1 of mbList)
  
return aMailBox
end getSelectedOneMailBox

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2008/04/12 選択中のメッセージの実ファイルが存在する場所を取得するv3

Mail.appで選択中のメッセージの実ファイルが存在するパスを取得します。MLから拾ってきたものをベースにサブルーチン化したものです。

スクリプト名:選択中のメッセージの実ファイルが存在する場所を取得するv3
Phillip Akerによる投稿を元にサブルーチン化
(*

philip@vcn.bc.ca
Subject: Re: Get .emlx file for Mail message?
Date: 2006年9月24日 18:49:39:JST
*)

set mRes to retSelectedMessagePath() of me

Mail.appで選択中のメッセージの実ファイルが存在するパスを取得する
on retSelectedMessagePath()
  set lpath to POSIX path of (path to library folder from user domain)
  
set res to {}
  
tell applicationMail
    set sels to (get selection)
    
if (sels = {}) or ((count of sels) is not equal to 1) then
      return false
    end if
    
    
repeat with i from 1 to count of sels
      set p to.mbox/Messages/
      
set m to mailbox of item i of sels
      
set mid to id of item i of sels
      
tell m
        set n to name
        
if (its account exists) then
          tell its account
            if (account type is not pop) then set p to.imapmbox/Messages/
            
set end of res to account directory & “/” & n & p & mid & “.emlx
          end tell
        else
          set c to its container
          
set p to n & p
          
repeat while c exists
            set p to c’s name & “/” & p
            
set c to c’s container
          end repeat
          
set end of res to lpath & “Mail/Mailboxes/” & p & mid & “.emlx
        end if
      end tell
    end repeat
  end tell
  
set aRes to item 1 of res
  
set fPath to POSIX file aRes
  
return fPath
end retSelectedMessagePath

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2008/04/12 添付ファイルのダウンロード先を求める

Mail.appの添付ファイルのダウンロード先フォルダを取得します。

スクリプト名:添付ファイルのダウンロード先を求める
download_path() of me

on download_path()
  set p to (path to preferences folder from user domain ?
    as Unicode text) & “com.apple.mail.plist
  tell applicationSystem Eventsto set f to value of ?
    property list itemMailDownloadsPathof property list file p & “/
  if f does not start with~then return f
  
set h to POSIX path of (path to home folder)
  
if (count f) < 3 then return h
  
h & f’s text 3 thru -1
end download_path

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2008/04/12 Mail.appで選択中のメッセージから迷惑メールフラグの状態を取得する

Mail.appで選択中のメッセージから迷惑メールフラグの状態を取得するサンプルです。メッセージは複数選択されている場合もあるため、それに対応しておく必要があります。

スクリプト名:Mail.appで選択中のメッセージから迷惑メールフラグの状態を取得する
tell applicationMail
  set a to selection
  
set b to item 1 of a
  
tell b
    set c to junk mail status
  end tell
end tell

> false

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2008/04/12 Mail.appで現在選択されているメールボックスの情報を取得する

Mail.appで現在選択中のメールボックスの情報を取得します。メッセージは選択されている場合と選択されていない場合があり、それぞれの状況を考慮しておく必要がありますが、メールボックスについては必ずどれかが選択されています。

mail5.jpg

スクリプト名:Mail.appで現在選択されているメールボックスの情報を取得する
tell applicationMail
  tell message viewer 1
    set mbList to selected mailboxes
  end tell
end tell

> {mailbox “ML/Apple US/ASに関係のあるもの/Apple Help” of application “Mail”}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2008/04/12 Mail.appでメッセージビューワーの情報を取得する

Mail.appでメッセージ表示用ビューワーウィンドウの情報を取得します。Mail.appは複数のビューワーウィンドウを同時に表示できるため、AppleScript側でもそれを考慮しておく必要があります。

mail3.jpg

mail4.jpg

スクリプト名:Mail.appでメッセージビューワーの情報を取得する
tell applicationMail
  count every message viewer
  
set aProp to properties of message viewer 1
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に