IMAPをコマンド操作する

接続

SSL使用しない場合

telnet imap.example.com 143

SSL通信する場合は openssl を使用する

openssl s_client -connect imap.gmail.com:993 -crlf -quiet

コマンド入力の基本

コマンド入力時は、行の先頭に識別子を付加して行う。

識別子  コマンド  引数/オプション等

コマンドに対する結果は、コマンド実行時に入力した識別子が付加して返却される。
※ソケット通信するプログラムを組む時は、レスポンスの最終行の判定に、この識別子が利用できる。
※コマンドを手入力する時は常に "?" 等を入力しても問題ない。

例) 識別子として test01 を指定して、メールボックス一覧を表示する場合

test01 list "" "*"                                                   # コマンド入力
* LIST (\HasNoChildren) "." "INBOX.Drafts"          # ↓ 以降はレスポンス
* LIST (\HasNoChildren) "." "INBOX.Trash"
* LIST (\HasNoChildren) "." "INBOX.Sent"
* LIST (\Unmarked \HasChildren) "." "INBOX"
test01 OK LIST completed                                  # レスポンスの最終行にも識別子が付加される

ログイン

a01 login test@example.com mail_password
a01 OK LOGIN Ok.

メールボックスの一覧表示

a02 list "" "*"
* LIST (\HasNoChildren) "." "INBOX.Drafts"
* LIST (\HasNoChildren) "." "INBOX.Trash"
* LIST (\HasNoChildren) "." "INBOX.Sent"
* LIST (\Unmarked \HasChildren) "." "INBOX"
a02 OK LIST completed

メールボックスの選択

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

メールの検索

a04 search all
* SEARCH 1 2 3 4 5 6 7 8 9
a04 OK SEARCH done.

メッセージ番号を指定してメールヘッダを取得する

a05 FETCH 2 RFC822.HEADER
* 2 FETCH (RFC822.HEADER {1015}
Return-Path: 
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 
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.

メッセージ番号を指定してメール内容を取得する

a06 FETCH 2 RFC822
* 2 FETCH (RFC822 {1434}
Return-Path: 
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 
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.

メッセージ番号を指定してメールを削除する

メールの削除はDeletedフラグを設定後に、EXPUNGE(Deletedフラグの立っているメールを削除する) を実行する。

a10 COPY 2 \"INBOX.Trash"                # 対象のメッセージ番号のメールをゴミ箱にコピーする
a11 STORE 2 +FLAGS (\Deleted)         # 対象のメッセージ番号のメールに Deleted フラグを立てる
a12 EXPUNGE                                     # Deleted フラグの立っているメールを削除する

phpで ソケット通信する例

接続/ログイン

$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;
  } 
} 

件名のデコード

Subject 等のヘッダは エンコードされた文字列から適切なデコード方法を判定できる。
ただし、長い件名等の時には、複数のデータに分割されているので、それぞれを個別にデコードした後に文字列結合する等の考慮が必要。
※ Fromヘッダ等もデコードが必要な場合がある。

PHPの例)

  public function decode_subject($line) {
    $subject = $line;
    if (preg_match_all("/=\?[a-zA-Z0-9\-_]+\?(B|Q)\?.+?\?=/", $subject, $ms)) {
      $matches = $ms[0];
      $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;
  } 

以下に例/イメージを記載する。

デコード前

=?utf-8?B?TWFj44GL44KJ6YCB5L+h44GX44Gf44OG44Kt44K544OI44Oh44O8?= =?utf-8?B?44Or?=

分割( ?文字コード?(B|Q)? 〜 ?= を 1つの纏まりとして分割する )

=?utf-8?B?TWFj44GL44KJ6YCB5L+h44GX44Gf44OG44Kt44K544OI44Oh44O8?=
=?utf-8?B?44Or?=

デコード後

=?utf-8?B?TWFj44GL44KJ6YCB5L+h44GX44Gf44OG44Kt44K544OI44Oh44O8?=  →  Macから送信したテキストメー
=?utf-8?B?44Or?=  →  ル

結合後

Macから送信したテキストメール

本文のデコード

Content-Type 及び Content-Transfer-Encoding の内容を参照してデコードを行う。
※ただし、multipartなメールの場合は、それぞれのパートの Content-Type 等を参照する必要がある。

TODO:

添付ファイルの取得

TODO:

multipart の取り扱いについて

TODO:

multipart/alternative なメールの取り扱い

TODO:

UIDを指定して各種操作を行うには

上記の例で使用しているメッセージ番号は、常に1〜連番で付番される為、メールの削除等を行うと変わってしまう。(不変の番号ではない)
なので、各種の操作を行う際には、ユニークなID(UID)を指定して操作を行う方が確実である。
※UIDは過去に渡って重複しないユニークな値。

UIDを指定してコマンド実行を行うには、コマンドの前に "UID" を入力する。

例)

# SEARCHの結果をUIDで表示する
a04 UID SEARCH ALL
* SEARCH 1 5 8 10 12
a04 OK SEARCH done.

# UID=10 を指定してメールヘッダを取得する
a05 UID FETCH 10 RFC822.HEADER
* 10 FETCH (RFC822.HEADER {1015}
Return-Path: 
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 なども可能。


トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-01-05 (木) 20:49:31 (710d)