前回、Telnetを使いSMTPサーバにアクセスしました。今回も前回と同様にArduino君にやってもらう前に、手動でメール(POP3)サーバにアクセスして試してみます。なおPOP3コマンドはwww.atmarkit.co.jpさんのWebに詳しく書いてあります。
[POP3 サーバにtelnetで接続してメールを読み込む]
telnet POP3サーバアドレス 110 Connected to mail.hogehoge.co.jp. Escape character is '^]'. +OK Hello there. <24680.1326193375@mail.hogehoge.co.jp> USER ユーザー名 +OK Password required. PASS メールパスワード +OK logged in. STAT ;メールの数とサイズを尋ねる。 +OK 2 2632 ;2通あることがわかります。 RETR n ;n番目のメールを表示する。 +OK message follows Return-Path: baz@foobar.co.jp Received: from deredere006.hogehoge.co.jp (LHLO deredere006.hogehoge.co.jp) (118.23.178.10) by daradara001.hogehoge.co.jp with LMTP; Tue, 10 Jan 2012 19:23:01 +0900 (JST) ・・・ 以下内容表示 ・・・ QUIT ;通信終了 +OK Bye-bye. Connection closed by foreign host.
私のプロバイダのPOP3サーバでは、このようなやり取りになりました。黒字はPOP3サーバが表示した文字ですが、POP3サーバの種類によって異なる場合があります。さてさて手動では問題なくつながりました。でも、これからどうしたものでしょう。今回も諸先輩の知恵をお借りしました。
そこで、ようやくみつけたのがこのMy Open Source Projects さんのArduino POP3 Email Checker です。(Thx Mr. Torchris!!)
こちらの作品は、LEDを使ってメールの数を知らせていますね。さすがです。でも、私は当初の予定通りシリアルモニタに表示させるだけにして置きましょう。実を言うと、ここにたどり着くまでに精魂使い果たしてしまいました。もう、余力がありません。ほんとです。
こちらに書かれていたコードを見て、おぼろげながら分かってきました。POP3サーバから表示されるデータは全部POP3コマンドを送信してから取り込めばよいみたいです。この参考スケッチではQUIT(終了)まで指示を行った後にデータを取り込んでいます。
だいたい理解できました、この作者が参考にしたお手本を元にしてスケッチを作ります。ほぼそのまんまです。
/* Simple POP3 Email Checker Arduino 1.0 version */ #include <Ethernet.h> #include <SPI.h> byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; byte ip[] = { 192, 168, xxx, xxx }; // Arduino EtherShield IP address byte gateway[] = { 192,168, xxx, xxx }; // Default Gateway IP address byte subnet[] = { 255, 255, 255, 0 }; // Subnet Mask byte server[] = { xxx,xxx,xxx,xxx }; // POP3 server address EthernetClient client; long updateTimer; boolean clientConnected = false; void setup() { Serial.begin(9600); } void loop() { if ((millis() - updateTimer) > 10000) { Ethernet.begin(mac, ip ,subnet,gateway ); //Arduino 1.0 see http://arduino.cc/forum/index.php?topic=83800.0 delay(1000); Serial.println("connecting..."); if (client.connect(server, 110)) //POP3 port 110 { Serial.println("connected"); client.println("user ユーザー名"); client.println("pass パスワード"); client.println("stat"); client.println("retr 1"); client.println("QUIT"); clientConnected = true; // **** (2) **** } else { Serial.println("connection failed"); } updateTimer = millis(); } if (clientConnected) { if (client.available()) { char c = client.read(); // ***** (1) ***** Serial.print(c); // ***** (1) ***** } if (!client.connected()) { Serial.println("disconnecting."); client.stop(); clientConnected = false; } } }
まず試しに、上記のスケッチでメールの数と、1番目のメールを表示させることができました。
これで、サーバから受け取ったすべての文字の表示をすることができました。さて、STATで表示されるメール数を取り出すにはどうすればよいでしょうか?
こちらもいろいろ検索してわかりました。find()関数とparseInt()関数を使って取り出します。先程の例で、サーバから送られてくる文字列は以下の通りです
Connected to mail.hogehoge.co.jp. Escape character is '^]'. +OK Hello there. <24680.1326193375@mail.hogehoge.co.jp> +OK Password required. +OK logged in. +OK 2 2632 ;この2をゲットしたい ・・・
ストリームクラスで使うfind()関数ですが、この場合ちょっとだけ工夫が必要です。4番目の”+OK”にヒットさせてparseInt()関数でメールの数を取り込みますが、今回は同じ文字列が複数あるので2段階にしなければなりません。
if ( client.find("+OK logged in.")) { client.find("+OK "); int count = client.parseInt(); Serial.print(" Your mail = "); Serial.println(count); }
(****** (1) ***** の場所を書き換えます)
これで良いはずだと思っていたのですが実際動かしてみると、うまくいきませんでした。結局のところ、理由不明ですがfind()関数を使う前にディレイを入れないと動かない事が分かりました。 苦労をしたので、この事を発見した時は少し涙が出てきてしまいました。この事象はArduino 1.0 に限った、特有の事かもしれません。
delay(1000); //この数値が適切か否かはわかりませんが、必要でした
(****** (2) ***** の場所に書き加えます)
ようやく完成しました。(・・・・と、喜んでいたのですが、しばらく動かしていると止まってしまいます。残念。原因が分かりません。前途多難です。)