[トップページへ戻る]・[ブログへ]


MacのMail.appで受信したメールが『安全』かどうかを判断するプログラムを作ってみました。

全てを弾く事はなかなか困難ではありますが、判断材料として使えるようにしました。

source4_2.jpg

プログラミングエディタ:スクリプトエディタ

開発環境:MacOS 12.3 Monterey

     スクリプトエディタv2.11(227)

     AppleScript 2.8

使用:NSWindow, NSView, NSTableView, NSScrollView, NSTextField, NSTextView, NSButton, 

   NSProgressIndicator, NSFont, NSColor, NSMakeRect, NSMakeSize, などです。


Mail.appの『全て』または『選択部分』または『未読部分』のメールを表示し、それが危険か注意が必要かを表示します。また、メッセージ項目をダブルクリックする事で詳細を表示します。

Mail.appが起動してることが必要です(プログラムを実行すると自動で立ち上がります)

source4_1.jpg


すべてのソース

use AppleScript version "2.7"

use scripting additions

use framework "Foundation"

use framework "AppKit"


global myApp

global theWindow, mainView

global closeFlg


property theDataSource : {}

global scrollView1, tableView1, sourceList

global button1, button2, button3, view1, textView1, textField1, progressIndicator1

global mailList, mailNo



on run

launch application "Mail"

--

my performSelectorOnMainThread:"mainMakeObject:" withObject:(missing value) waitUntilDone:true

--

log "End"

end run


on mainMakeObject:inputObj

set myApp to current application

set closeFlg to false

set aTitle to "Suspicious email"

set aRect to {300, 150, 1000, 640}

set moveCenter to true

set theWindow to my makeNewWindow(aTitle, aRect, moveCenter)

my makeObject()

theWindow's setAlphaValue:1.0

--

repeat

if closeFlg then

my closeWin:theWindow

exit repeat

end if

delay 0.2

end repeat

end mainMakeObject:


on makeNewWindow(aTitle, aRect, moveCenter)

set {windowX, windowY, windowW, windowH} to aRect

set theRect to myApp's NSMakeRect(windowX, windowY, windowW, windowH)

set aScreen to myApp's class "NSScreen"'s mainScreen()

set aStyle to (myApp's NSWindowStyleMaskTitled as integer)

set aStyle to aStyle + (myApp's NSWindowStyleMaskClosable as integer)

set aStyle to aStyle + (myApp's NSWindowStyleMaskMiniaturizable as integer)

set aStyle to aStyle + (myApp's NSWindowStyleMaskResizable as integer)

set aBacking to myApp's NSBackingStoreBuffered

set aWindow to myApp's class "NSWindow"'s alloc()'s initWithContentRect:theRect styleMask:aStyle backing:aBacking defer:false screen:aScreen

tell aWindow

setAlphaValue_(0.0)

setDelegate_(me)

setTitle_(aTitle)

setMinSize_(myApp's NSMakeSize(640, 420))

setMaxSize_(myApp's NSMakeSize(10000, 10000))

setBackgroundColor_(myApp's class "NSColor"'s colorWithCalibratedRed:0.95 green:0.95 blue:0.95 alpha:1.0)

setDisplaysWhenScreenProfileChanges_(true)

setReleasedWhenClosed_(true)

makeKeyAndOrderFront_(me)

end tell

--

if moveCenter then

aWindow's |center|()

set theScreen to myApp's class "NSScreen"'s screens()

set {windowCenterX, winsowCenterY} to {windowX + (windowW / 2), windowY + (windowH / 2)}

repeat with screenNo from 1 to (count of theScreen)

set {{screenX1, screenY1}, {screenWidth, screenHeight}} to (item screenNo of theScreen)'s frame()

set {screenX2, screenY2} to {screenX1 + screenWidth, screenY1 + screenHeight}

if (windowCenterX > screenX1) and (windowCenterX < screenX2) and (winsowCenterY > screenY1) and (winsowCenterY < screenY2) then

set originX to screenX1 + (screenWidth / 2) - (windowW / 2)

set originY to screenY1 + (screenHeight / 2) - (windowH / 2)

(aWindow's setFrameOrigin:(myApp's NSMakePoint(originX, originY)))

exit repeat

end if

end repeat

end if

--

return aWindow

end makeNewWindow


(* 各オブジェクトの配置 *)

on makeObject()

set mainView to theWindow's contentView

set theWindowFrame to mainView's frame()

set {{windowX, windowY}, {windowWidth, windowHeight}} to theWindowFrame

--

set minXMargin to (myApp's NSViewMinXMargin) as integer -- 左の余白を柔軟に

set maxXMargin to (myApp's NSViewMaxXMargin) as integer -- 右の余白を柔軟に

set minYMargin to (myApp's NSViewMinYMargin) as integer -- 下の余白を柔軟に

set maxYMargin to (myApp's NSViewMaxYMargin) as integer -- 上の余白を柔軟に

set widthSizable to (myApp's NSViewWidthSizable) as integer -- 横方向の幅を柔軟に

set heightSizable to (myApp's NSViewHeightSizable) as integer -- 縦方向の幅を柔軟に

set fixedTopAndRight to minYMargin + minXMargin -- 右上を固定 天地左右の幅を固定

set freeSizeWidthHeight to widthSizable + heightSizable -- 天地左右の余白固定 天地左右の幅を自由に

set fixedButtomAndRight to maxYMargin + minXMargin -- 下と右を固定・幅固定

set freeTopBottomAndLeftRight to minXMargin + maxXMargin + minYMargin + maxYMargin --サイズはそのままで位置を自由に

--

try

-- 新しくオブジェクトを配置する部分 --------------------

(* TableView *)

set {x, y, w, h} to {3, 3, windowWidth - 83, windowHeight - 6}

set sourceList to {}

set theDataSource to myApp's class "NSMutableArray"'s alloc()'s init()

theDataSource's addObjectsFromArray:sourceList

set aColumn1 to myApp's class "NSTableColumn"'s alloc()'s initWithIdentifier:"data1"

tell aColumn1

headerCell()'s setTitle:"判定"

setEditable_(false)

setWidth_(50)

end tell

set aColumn2 to myApp's class "NSTableColumn"'s alloc()'s initWithIdentifier:"data2"

tell aColumn2

headerCell()'s setTitle:"送信者"

setEditable_(false)

setWidth_(220)

end tell

set aColumn3 to myApp's class "NSTableColumn"'s alloc()'s initWithIdentifier:"data3"

tell aColumn3

headerCell()'s setTitle:"タイトル"

setEditable_(false)

setWidth_(400)

end tell

set aColumn4 to myApp's class "NSTableColumn"'s alloc()'s initWithIdentifier:"data4"

tell aColumn4

headerCell()'s setTitle:"受信日"

setEditable_(false)

setWidth_(200)

end tell

set tableView1 to myApp's class "NSTableView"'s alloc()'s initWithFrame:(myApp's NSMakeRect(0, 0, w, h))

tell tableView1

setDelegate_(me)

addTableColumn_(aColumn1)

addTableColumn_(aColumn2)

addTableColumn_(aColumn3)

addTableColumn_(aColumn4)

setDataSource_(me)

setUsesAlternatingRowBackgroundColors_(true)

setDoubleAction_("tableAction:")

end tell

set scrollView1 to myApp's class "NSScrollView"'s alloc()'s initWithFrame:(myApp's NSMakeRect(x, y, w, h))

scrollView1's setDocumentView:tableView1

theWindow's contentView()'s addSubview:scrollView1

tell scrollView1

setHasHorizontalScroller_(true)

setHasVerticalScroller_(true)

setAutohidesScrollers_(true)

setAutoresizingMask_(freeSizeWidthHeight)

end tell

tableView1's reloadData()

(* TextField *)

set theRect to myApp's NSMakeRect(windowWidth - 73, windowHeight - 30, 75, 24)

set aTextField to myApp's class "NSTextField"'s alloc()'s initWithFrame:theRect

tell aTextField

setDelegate_(me)

setEditable_(false)

setBordered_(false)

setStringValue_("項目の取得")

setDrawsBackground_(false)

setAutoresizingMask_(fixedTopAndRight)

end tell

theWindow's contentView()'s addSubview:aTextField

(* Button 13 *)

set theRect to myApp's NSMakeRect(windowWidth - 80, windowHeight - 50, 80, 24)

set button1 to myApp's class "NSButton"'s alloc()'s initWithFrame:theRect

tell button1

setBezelStyle_(myApp's NSBezelStyleRounded)

setTitle_("全て")

setTarget_(me)

setAction_("buttonAction1:")

setAutoresizingMask_(fixedTopAndRight)

end tell

mainView's addSubview:button1

--

set theRect to myApp's NSMakeRect(windowWidth - 80, windowHeight - 75, 80, 24)

set button2 to myApp's class "NSButton"'s alloc()'s initWithFrame:theRect

tell button2

setBezelStyle_(myApp's NSBezelStyleRounded)

setTitle_("選択部分")

setTarget_(me)

setAction_("buttonAction2:")

setAutoresizingMask_(fixedTopAndRight)

end tell

mainView's addSubview:button2

--

set theRect to myApp's NSMakeRect(windowWidth - 80, windowHeight - 100, 80, 24)

set button3 to myApp's class "NSButton"'s alloc()'s initWithFrame:theRect

tell button3

setBezelStyle_(myApp's NSBezelStyleRounded)

setTitle_("未読部分")

setTarget_(me)

setAction_("buttonAction3:")

setAutoresizingMask_(fixedTopAndRight)

end tell

mainView's addSubview:button3

(* ProgressIndicator *)

set theRect to myApp's NSMakeRect((windowWidth / 2) - 85, (windowHeight / 2) - 25, 50, 50)

set progressIndicator1 to myApp's class "NSProgressIndicator"'s alloc()'s initWithFrame:theRect

tell progressIndicator1

setDoubleValue_(1.0)

setMinValue_(0.0)

setMaxValue_(1.0)

setStyle_(myApp's NSProgressIndicatorStyleSpinning)

setIndeterminate_(false)

setAlphaValue_(0.0)

setAutoresizingMask_(freeTopBottomAndLeftRight)

end tell

mainView's addSubview:progressIndicator1

(* TextField - message *)

set theRect to myApp's NSMakeRect((windowWidth / 2) - 160, (windowHeight / 2) - 70, 200, 25)

set textField1 to myApp's class "NSTextField"'s alloc()'s initWithFrame:theRect

tell textField1

setDelegate_(me)

setEditable_(false)

setBordered_(true)

setStringValue_("Controlキーで中止できます")

setAlignment_(myApp's NSTextAlignmentCenter)

setDrawsBackground_(true)

setBackgroundColor_(myApp's class "NSColor"'s yellowColor())

setAlphaValue_(0.0)

setAutoresizingMask_(freeTopBottomAndLeftRight)

end tell

theWindow's contentView()'s addSubview:textField1

(* SubView *)

set theRect to myApp's NSMakeRect(0, 0, windowWidth, windowHeight)

set view1 to myApp's class "NSView"'s alloc()'s initWithFrame:theRect

tell view1

setAlphaValue_(0.9)

view1's setHidden:true

setAutoresizingMask_(freeSizeWidthHeight)

end tell

mainView's addSubview:view1

(* view - shadow *)

set theRect to myApp's NSMakeRect(48, 45, windowWidth - 173, windowHeight - 93)

set view2 to myApp's class "NSView"'s alloc()'s initWithFrame:theRect

tell view2

setAlphaValue_(0.7)

setBackgroundColor_(myApp's class "NSColor"'s whiteColor())

setAutoresizingMask_(freeSizeWidthHeight)

end tell

view1's addSubview:view2

(* TextView *)

set {x, y, w, h} to {50, 50, windowWidth - 180, windowHeight - 100}

set theRect to myApp's NSMakeRect(x, y, w, h)

set scrollView1 to myApp's class "NSScrollView"'s alloc()'s initWithFrame:theRect

tell scrollView1

setBorderType_(myApp's NSLineBorder)

setHasVerticalScroller_(true)

setHasHorizontalScroller_(false)

setBackgroundColor_(myApp's class "NSColor"'s clearColor)

setAutoresizingMask_(freeSizeWidthHeight)

end tell

set textView1 to myApp's class "NSTextView"'s alloc()'s initWithFrame:theRect

tell textView1

setMinSize_(myApp's NSMakeSize(0, h))

setMaxSize_(myApp's NSMakeSize(10000, 10000))

setVerticallyResizable_(true)

setHorizontallyResizable_(false)

setAutoresizingMask_(widthSizable)

setString_("")

setEditable_(false)

textContainer()'s setContainerSize:(myApp's NSMakeSize(w, 10000))

textContainer()'s setWidthTracksTextView:true

end tell

scrollView1's setDocumentView:textView1

view1's addSubview:scrollView1

(* Button 4 *)

set theRect to myApp's NSMakeRect(windowWidth - 230, 55, 80, 24)

set button4 to myApp's class "NSButton"'s alloc()'s initWithFrame:theRect

tell button4

setBezelStyle_(myApp's NSBezelStyleRounded)

setTitle_("閉じる")

setTarget_(me)

setAction_("buttonAction4:")

setAutoresizingMask_(fixedButtomAndRight)

end tell

view1's addSubview:button4

--

set theRect to myApp's NSMakeRect(windowWidth - 320, 55, 80, 24)

set button5 to myApp's class "NSButton"'s alloc()'s initWithFrame:theRect

tell button5

setBezelStyle_(myApp's NSBezelStyleShadowlessSquare)

setTitle_("ゴミ箱へ")

setTarget_(me)

setAction_("buttonAction5:")

setAutoresizingMask_(fixedButtomAndRight)

end tell

view1's addSubview:button5

----------------------------------------------------------

on error errText

log errText

end try

end makeObject


on buttonAction1:sender

tell application "Mail" to set mailList to messages of inbox

my getMailList(mailList)

end buttonAction1:


on buttonAction2:sender

tell application "Mail" to set mailList to selection

my getMailList(mailList)

end buttonAction2:


on buttonAction3:sender

button1's setEnabled:false

button2's setEnabled:false

button3's setEnabled:false

textField1's setAlphaValue:0.8

tell progressIndicator1

setAlphaValue_(1.0)

setDoubleValue_(0.0)

setIndeterminate_(true)

startAnimation_(true)

end tell

tell application "Mail" to set aList to messages of inbox

set mailList to {}

repeat with aMail in aList

(* 中断受付 *)

set bitKey to 18 -- {Shift=17,Control=18,Option=19,Command=20}

set bitNo to 2 ^ bitKey

set ans to myApp's class "NSEvent"'s modifierFlags()

if ((ans div bitNo) mod 2) = 1 then

(textField1's setAlphaValue:0)

(progressIndicator1's setAlphaValue:0.0)

(button1's setEnabled:true)

(button2's setEnabled:true)

(button3's setEnabled:true)

return -- "STOP"

end if

tell application "Mail"

set f to read status of aMail

if f = false then

set ans to aMail

set mailList to mailList & {ans}

end if

end tell

end repeat

tell progressIndicator1

stopAnimation_(true)

setIndeterminate_(false)

end tell

my getMailList(mailList)

end buttonAction3:


on buttonAction4:sender

tableView1's setEnabled:true

view1's setHidden:true

end buttonAction4:


on buttonAction5:sender

set tagetMail to item (mailNo + 1) of mailList

delete tagetMail

if mailNo = 0 then

set sourceList to items 2 thru -1 of sourceList

else if mailNo = ((count of sourceList) - 1) then

set sourceList to items 1 thru -2 of sourceList

else

set sourceList to (items 1 thru mailNo of sourceList) & (items (mailNo + 2) thru -1 of sourceList)

end if

set theDataSource to myApp's class "NSMutableArray"'s alloc()'s init()

theDataSource's addObjectsFromArray:sourceList

tableView1's reloadData()

tableView1's setEnabled:true

view1's setHidden:true

end buttonAction5:


on tableAction:sender

textView1's setString:""

textView1's setBackgroundColor:(myApp's class "NSColor"'s colorWithCalibratedRed:0.9 green:0.93 blue:0.97 alpha:1.0)

tableView1's setEnabled:false

delay 0.3

view1's setHidden:false

set mailNo to sender's clickedRow()

set tagetMail to item (mailNo + 1) of mailList

set {text1, text2} to mailEmergencyCheck(tagetMail)

set commentText to return & text2 & return & return & return & text1

textView1's setString:commentText

if text2 ≠ "" then

tableView1's setBackgroundColor:(myApp's class "NSColor"'s colorWithCalibratedRed:1.0 green:0.95 blue:0.95 alpha:0.8)

end if

end tableAction:


on getMailList(mailList) -- メールリスト取得

button1's setEnabled:false

button2's setEnabled:false

button3's setEnabled:false

tableView1's setAlphaValue:0.5

progressIndicator1's setAlphaValue:1.0

textField1's setAlphaValue:0.8

try

set sourceList to {}

set countMail to count of mailList

set i to 0

repeat with aMail in mailList

(* 中断受付 *)

set bitKey to 18 -- {Shift=17,Control=18,Option=19,Command=20}

set bitNo to 2 ^ bitKey

set ans to myApp's class "NSEvent"'s modifierFlags()

if ((ans div bitNo) mod 2) = 1 then exit repeat -- "STOP"

--

set i to i + 1

set aCheckText to "-"

set {text1, text2} to mailEmergencyCheck(aMail)

if text2 contains "危険" then

set aCheckText to "危険"

else if text2 contains "注意" then

set aCheckText to "注意"

else

set aCheckText to "-"

end if

tell application "Mail"

set aAddress to sender of aMail

if aAddress contains ">" then set aAddress to rich text ((offset in aAddress of "<") + 1) thru ((offset in aAddress of ">") - 1)   ¬

of aAddress

set aSubject to subject of aMail

set aDate to (date sent of aMail) as rich text

end tell

set sourceList to sourceList & {{data1:aCheckText, data2:aAddress, data3:aSubject, data4:aDate}}

set c to count of sourceList

if ((c mod 5) = 0) and (c < 50) then

set theDataSource to myApp's class "NSMutableArray"'s alloc()'s init()

(theDataSource's addObjectsFromArray:sourceList)

tableView1's reloadData()

end if

set aValue to i / countMail

(progressIndicator1's setDoubleValue:aValue)

end repeat

set theDataSource to myApp's class "NSMutableArray"'s alloc()'s init()

theDataSource's addObjectsFromArray:sourceList

tableView1's reloadData()

on error errText

log errText

end try

tableView1's setAlphaValue:1.0

button1's setEnabled:true

button2's setEnabled:true

button3's setEnabled:true

progressIndicator1's setAlphaValue:0.0

textField1's setAlphaValue:0.0

end getMailList


on mailEmergencyCheck(aMail) -- 危険度判定

set CR to ASCII character 13

tell application "Mail"

set aSender to sender of aMail

set aSubject to subject of aMail

set aContent to content of aMail

set aHeaders to all headers of aMail

end tell

set commentText to "● 送信者:" & CR & "  " & aSender & CR & "● メールタイトル:" & CR & "  " & aSubject & CR & "● 本文:" & CR &  ¬

aContent & CR & CR

set emergencyText to ""

(* 二重アドレス偽装の確認 -???@???.jp.xxx.xxx』のようなアドレス偽装かどうか? *)

if (aSender contains ".co.jp.") or (aSender contains ".or.jp.") or (aSender contains ".ad.jp.") or (aSender contains ".ne.jp.") or  ¬

(aSender contains ".com.") then set emergencyText to emergencyText & "危険:送信者のアドレスに異常を発見" & CR

if (aSender contains ".net.") or (aSender contains ".org.") then set emergencyText to emergencyText & "危険:送信者のアドレスに異常を発見" & CR

(* 末尾が、”.jp””.com” などでないものではないのか? *)

set add to aSender

if (character -1 of add) = ">" then set add to text 1 thru -2 of add

if not ((add ends with ".jp") or (add ends with ".com") or (add ends with ".net") or (add ends with ".org")) then set emergencyText to emergencyText & "注意:送信者のドメインが想定外でした。" & CR

(* 本文中に二重アドレス偽装がないか? *)

if (aContent contains ".co.jp.") or (aContent contains ".or.jp.") or (aContent contains ".ad.jp.") or (aContent contains ".ne.jp.") or  ¬

(aContent contains ".com.") then set emergencyText to emergencyText & "危険:本文中のアドレスに異常を発見" & CR

if (aSender contains ".net.") or (aSender contains ".org.") then set emergencyText to emergencyText &  ¬

"危険:本文中のアドレスに異常を発見" & CR

(* ヘッダーに異常 1 *)

repeat with oneLine in (paragraphs of aHeaders)

if (oneLine contains "Message-ID") then

--log oneLine

set senderAdd to text ((offset in oneLine of "@") + 1) thru ((offset in oneLine of ">") - 1) of oneLine

repeat with oneLine in (paragraphs of aHeaders)

if (oneLine contains senderAdd) and (oneLine contains "Received") and (oneLine contains "(unknown [") then

set emergencyText to emergencyText & ¬

  "注意:ヘッダーの送信者情報にunknownを発見" & CR & "  (たまに設定していないだけのサーバーがあるので一概には..." & CR

exit repeat

end if

end repeat

end if

end repeat

(* ヘッダーに異常 2 *)

set objList to {{"Amazon", "amazon"}, {"アマゾン", "amazon"}, {"Rakuten", "rakuten"}, {"楽天", "rakuten"}, ¬

{"イオンカード", "aeon.co.jp"}, {"三井住友カード", "smbc-card.com"}, {"エポスカード", "eposcard.co.jp"}, ¬

{"セゾンカード", "saisoncard.co.jp"}, {"セブンカード", "7card.co.jp"}, {"Suica", "suica"}, {"コスモ", "cosmo"}, ¬

{"三菱UFJカード", "mufg.jp"}, {"ライフカード", "lifecard-promotion-dg.com"}, {"eneos", "eneos.co.jp"}, ¬

{"Americanexpress", "americanexpress.com"}, {"アメリカン・エキスプレス", "americanexpress.com"}, ¬

{"JR西日本", "jr-odekake"}, {"J-WEST", "jr-odekake"}, {"Adobe", "adobe.com"}, {"アドビ", "adobe.com"}, ¬

{"マイクロソフト", "microsoft"}, {"Microsoft", "microsoft"}, {"JR東日本", "jr-odekake"}, {"J-EAST", "jr-odekake"}, ¬

{"郵便局", "japanpost.jp"}} -- , {"", ""}

repeat with oneLine in (paragraphs of aHeaders)

if (oneLine contains "差出人: ") then

set c to offset in oneLine of "<"

if c > 1 then

set text1 to text 1 thru (c - 1) of oneLine

set text2 to text (offset in oneLine of "@") thru -1 of oneLine

repeat with obj in objList

set {key1, key2} to obj

if text1 contains key1 then

if not (text2 contains key2) then set emergencyText to emergencyText & "危険:送信者名に偽装の可能性" & CR

end if

end repeat

end if

exit repeat

end if

end repeat

--

if emergencyText = "" then set emergencyText to "(異常は発見されませんでした。)"

return {commentText, emergencyText}

end mailEmergencyCheck


(* TableViewの表示行数処理(必須) *)

on numberOfRowsInTableView:tableView1

set c to count of (my theDataSource)

return c

end numberOfRowsInTableView:


(* TableViewデータの処理(必須) *)

on tableView:tableView1 objectValueForTableColumn:aColumn row:aRow

set aRec to (my theDataSource)'s objectAtIndex:(aRow as number)

set aIdentifier to (aColumn's identifier()) as string

set aRes to (aRec's valueForKey:aIdentifier)

return aRes

end tableView:objectValueForTableColumn:row:


(* ウインドウバーの閉じるボタンアクションを受けた時 *)

on windowShouldClose:sender

set closeFlg to true

end windowShouldClose:


(* ウインドウを閉じるための実際のアクション *)

on closeWin:aWindow

aWindow's orderOut:me

if (name of myApp) ≠ "Script Editor" then quit me

end closeWin:




[トップページへ戻る]・[ブログへ]

inserted by FC2 system