* IMAPをコマンド操作する [#hbecbce1] #setlinebreak(on) #contents -- 参考 --- http://www.atmarkit.co.jp/ait/articles/0106/13/news001.html --- http://www.atmarkit.co.jp/fnetwork/rensai/netpro09/imap4-command.html --- http://www.atmarkit.co.jp/fnetwork/rensai/netpro09/imap4-fetch.html ** 接続 [#j06dc8a3] SSL使用しない場合 #myterm2(){{ telnet imap.example.com 143 }} SSL通信する場合は openssl を使用する #myterm2(){{ openssl s_client -connect imap.gmail.com:993 -crlf -quiet }} ** コマンド入力の基本 [#z6eb12d8] コマンド入力時は、行の先頭に識別子を付加して行う。 #myterm2(){{ 識別子 コマンド 引数/オプション等 }} コマンドに対する結果は、コマンド実行時に入力した識別子が付加して返却される。 ※ソケット通信するプログラムを組む時は、レスポンスの最終行の判定に、この識別子が利用できる。 ※コマンドを手入力する時は常に "?" 等を入力しても問題ない。 例) 識別子として test01 を指定して、メールボックス一覧を表示する場合 #myterm2(){{ test01 list "" "*" # コマンド入力 * LIST (\HasNoChildren) "." "INBOX.Drafts" # ↓ 以降はレスポンス * LIST (\HasNoChildren) "." "INBOX.Trash" * LIST (\HasNoChildren) "." "INBOX.Sent" * LIST (\Unmarked \HasChildren) "." "INBOX" test01 OK LIST completed # レスポンスの最終行にも識別子が付加される }} ** ログイン [#m751943c] #myterm2(){{ a01 login test@example.com mail_password a01 OK LOGIN Ok. }} ** メールボックスの一覧表示 [#p3339d83] #myterm2(){{ a02 list "" "*" * LIST (\HasNoChildren) "." "INBOX.Drafts" * LIST (\HasNoChildren) "." "INBOX.Trash" * LIST (\HasNoChildren) "." "INBOX.Sent" * LIST (\Unmarked \HasChildren) "." "INBOX" a02 OK LIST completed }} ** メールボックスの選択 [#nb1a1564] #myterm2(){{ a03 select "INBOX" * FLAGS (\Draft \Answered \Flagged \Deleted \Seen \Recent) * OK [PERMANENTFLAGS (\* \Draft \Answered \Flagged \Deleted \Seen)] Limited * 9 EXISTS * 0 RECENT * OK [UIDVALIDITY 1483004963] Ok * OK [MYRIGHTS "acdilrsw"] ACL a03 OK [READ-WRITE] Ok }} ※ ** メールの検索 [#ieef46df] #myterm2(){{ a04 search all * SEARCH 1 2 3 4 5 6 7 8 9 a04 OK SEARCH done. }} ** メッセージ番号を指定してメールヘッダを取得する [#ea0ac166] #myterm2(){{ a05 FETCH 2 RFC822.HEADER * 2 FETCH (RFC822.HEADER {1015} Return-Path: <test@example.com> Delivered-To: example.com-test@example.com X-Spam-Checker-Version: SpamAssassin X.X.X (XXXX-XX-XX) on xxxx.xxxxx.com . . Received: (qmail 12845 invoked by uid 89); 29 Dec 2016 18:50:58 +0900 From: XXXXX XXXXX <test@example.com> Content-Type: text/plain; charset=iso-2022-jp Content-Transfer-Encoding: 7bit Mime-Version: 1.0 (1.0) Date: Thu, 29 Dec 2016 18:50:57 +0900 Subject: test2 Message-Id: XXXXXXXXXXXXXXXXXXXXXXX To: test@example.com ) a05 OK FETCH completed. }} ** メッセージ番号を指定してメール内容を取得する [#obe1ec66] #myterm2(){{ a06 FETCH 2 RFC822 * 2 FETCH (RFC822 {1434} Return-Path: <test@example.com> Delivered-To: example.com-test@example.com X-Spam-Checker-Version: SpamAssassin X.X.X (XXXX-XX-XX) on xxxx.xxxxx.com . . Received: (qmail 12845 invoked by uid 89); 29 Dec 2016 18:50:58 +0900 From: XXXXX XXXXX <test@example.com> Content-Type: text/plain; charset=iso-2022-jp Content-Transfer-Encoding: 7bit Mime-Version: 1.0 (1.0) Date: Thu, 29 Dec 2016 18:50:57 +0900 Subject: test2 Message-Id: XXXXXXXXXXXXXXXXXXXXXXX To: test@example.com test2 ) a06 OK FETCH completed. }} ** メッセージ番号を指定してメールを削除する [#ea4146d8] メールの削除はDeletedフラグを設定後に、EXPUNGE(Deletedフラグの立っているメールを削除する) を実行する。 #myterm2(){{ a10 COPY 2 \"INBOX.Trash" # 対象のメッセージ番号のメールをゴミ箱にコピーする a11 STORE 2 +FLAGS (\Deleted) # 対象のメッセージ番号のメールに Deleted フラグを立てる a12 EXPUNGE # Deleted フラグの立っているメールを削除する }} ** phpで ソケット通信する例 [#h4ff8c50] *** 接続/ログイン [#pa030ae5] #mycode2(){{ $fp = fsockopen("imap.example.com", "143", $errno, $errstr); //SSL通信しない場合 // $fp = fsockopen("ssl://imap.gmail.com", "993", $errno, $errstr); // SSL通信する場合 fputs($fp,"A01 login {$username} {$password}\r\n"); while (true) { $line = fgets($fp); if (preg_match("/(NO |failed|Failure)/i", $line)) { // ログインエラー fclose($fp); } if (preg_match("/^A01 /", $line)) { // 最終行 break; } } }} *** 件名のデコード [#j1e76d33] Subject 等のヘッダは エンコードされた文字列から適切なデコード方法を判定できる。 ただし、長い件名等の時には、複数のデータに分割されているので、それぞれを個別にデコードした後に文字列結合する等の考慮が必要。 ※ Fromヘッダ等もデコードが必要な場合がある。 PHPの例) #mycode2(){{ public function decode_subject($line) { $subject = preg_replace("/\?= /", "?=", $line); if (preg_match_all("/=\?.*?\?=/", $subject, $ms)) { $subject = $line; if (preg_match_all("/=\?[a-zA-Z0-9\-_]+\?(B|Q)\?.+?\?=/", $subject, $ms)) { $matches = $ms[0]; $charset = preg_replace("/[^a-zA-Z0-9\-_]/", "", preg_replace("/\?.+$/", "", preg_replace("/^=\?/", "", $subject))); $rep = []; foreach ($matches as $i => $str) { $charset = preg_replace("/[^a-zA-Z0-9\-_]/", "", preg_replace("/\?.+$/", "", preg_replace("/^=\?/", "", $str))); $subject_piece = $line; if (preg_match("/=\?".$charset."\?(B|Q)\?/i", $str, $ms)) { //$subject_piece = mb_decode_mimeheader($str); $subject_piece = preg_replace("/\?=/", "", preg_replace("/=\?".$charset."\?(B|Q)\?/i", "", $str)); if ($ms[1] == "B") { $subject_piece = mb_convert_encoding(base64_decode($subject_piece), "utf-8", $charset); } else { $subject_piece = mb_convert_encoding(quoted_printable_decode($subject_piece), "utf-8", $charset); } } $rep[$i] = $subject_piece; } $subject = preg_replace("/\?=( |\t|\r\n|\r|\n)+=\?/", "?==?", $subject); // パート間のスペースを削除 foreach ($matches as $i => $str) { $subject = str_replace($str, $rep[$i], $subject); $subject = str_replace($str, "", $subject); } } else { $subject = mb_convert_encoding($subject, "UTF-8", "auto"); } return $subject; } } }} 以下に例/イメージを記載する。 デコード前 #mycode(){{ =?utf-8?B?TWFj44GL44KJ6YCB5L+h44GX44Gf44OG44Kt44K544OI44Oh44O8?= =?utf-8?B?44Or?= }} 分割( ?文字コード?(B|Q)? 〜 ?= を 1つの纏まりとして分割する ) #mycode(){{ =?utf-8?B?TWFj44GL44KJ6YCB5L+h44GX44Gf44OG44Kt44K544OI44Oh44O8?= =?utf-8?B?44Or?= }} デコード後 #mycode(){{ =?utf-8?B?TWFj44GL44KJ6YCB5L+h44GX44Gf44OG44Kt44K544OI44Oh44O8?= → Macから送信したテキストメー =?utf-8?B?44Or?= → ル }} 結合後 #mycode(){{ Macから送信したテキストメール }} *** 本文のデコード [#wec292ad] Content-Type 及び Content-Transfer-Encoding の内容を参照してデコードを行う。 ※ただし、multipartなメールの場合は、それぞれのパートの Content-Type 等を参照する必要がある。 #todo *** 添付ファイルの取得 [#d28914ab] #todo *** multipart の取り扱いについて [#y327eeba] #todo *** multipart/alternative なメールの取り扱い [#d7dfaf7f] #todo ** UIDを指定して各種操作を行うには [#v0692d08] 上記の例で使用しているメッセージ番号は、常に1〜連番で付番される為、メールの削除等を行うと変わってしまう。(不変の番号ではない) なので、各種の操作を行う際には、ユニークなID(UID)を指定して操作を行う方が確実である。 ※UIDは過去に渡って重複しないユニークな値。 UIDを指定してコマンド実行を行うには、コマンドの前に "UID" を入力する。 例) #myterm2(){{ # SEARCHの結果をUIDで表示する a04 <strong>UID</strong> SEARCH ALL * SEARCH 1 5 8 10 12 a04 OK SEARCH done. # UID=10 を指定してメールヘッダを取得する a05 <strong>UID</strong> FETCH 10 RFC822.HEADER * 10 FETCH (RFC822.HEADER {1015} Return-Path: <test@example.com> Delivered-To: example.com-test@example.com X-Spam-Checker-Version: SpamAssassin X.X.X (XXXX-XX-XX) on xxxx.xxxxx.com . . &color(#f00){インライン要素}; }} 他にも、COPY、FETCH、STORE なども可能。