【PC】Android で Socketを使ったメール送信(3)
前回、SMTPへの接続と HELOコマンドのお話をした。connection(socket)という通信係と reader=耳 と writer=口があれば、接続して→命令して→回答をチェックしてと繰り返していけばよい。しかし1つのコマンドに対して1つの回答しかない、のであればそれだけでよいのだが、実際には、1つしか命令していないのに、大量の回答を早口でまくしたててきたりするのが SMTPサーバーだ。
接続時には、うまくいけば「220」の1行だけ回答がある。
しかし「HELO」に対しては、私はこういうものです、私はこういうもので、接続はこのようにしています、みたいに、ずらずらっと回答がある。
このため「reader で読む」だけでは最後まで読めず、あとの処理に支障がある。「readerで読む」「readerで読む」「readerで読む」を繰り返し、最後の行まで読み込まないと、あとが続かない。
(読み残しが出来てしまうと、今 readした回答が、今命令したものに対してなのか、さきほどの命令に対するものかがわからなくなってしまう)
そこで、read専用の関数を作成する。ついでに write関数も作成してしまおう。メインの処理からは、この関数を介して通信することにする。
「HELO」への回答は、うまくいけば「250」から始まる行が数行返される。この中には、あとで処理する予定の認証方法や、接続の状態などの情報が記載される。1行だけというのは、まずない。ただ、3ケタのコード番号の後ろに、続きがある場合は(次の行がある場合は)「-」がついてくるので、これで最後の行(すなわち3ケタのコードの後ろに「-」ではなく空白になっている行)までを ループ処理で読み込んであげれば、全部の回答を読むことができる。
回答データには重要な話しがたくさん掲載されているのだが、最後の行のコードだけ見れば十分というお手軽処理でメール送信をしていくことにする。
通常通りに1文を受信し、戻り値にセット。
4ケタ目(4バイト目)の文字をチェックして「-」でなければループを抜ける。
「-」だった場合は続きがあるので、ループ(再度受信する)
// // データ受信関数 // private String readData( BufferedReader reader ){ String ret = ""; String message; try { while( (message = reader.readLine())!=null ){ ret = message; if( message.length()>4 ){ if( !message.substring(3,3+1).equals("-") ){ // 3ケタのコードの後が "-" なら継続行があるので続ける break; } } } } catch (IOException e) { } return ret; } // // オマケ:データ送信関数 // private Boolean sendData( BufferedWriter writer,String msg ) throws IOException{ Boolean ret = true; writer.write( msg ); writer.flush(); return ret; }
オマケとしてあるデータ送信の方は、writerに値をセット、writeとflushメソッドで実際に送信するだけ。これで前々回のプログラムを書き直すと、以下の通り。( reader部分が違うだけだが(笑))
public Boolean sendMail( String smtphost, int smtpport, String fromName, String fromMailAddress, String toMailAddress, String subject, String bodymsg ){ Boolean ret = true; Socket connection = null; BufferedReader reader = null; BufferedWriter writer = null; try { // サーバーに接続 connection = new Socket( smtphost,smtpport ); reader = new BufferedReader( new InputStreamReader( connection.getInputStream() ) ); writer = new BufferedWriter( new OutputStreamWriter( connection.getOutputStream(),"ISO2022JP" ) ); String message = readData(reader); if ( !message.startsWith("220") ) return false; // HELOの送信 sendData( writer, "EHLO " + smtphost + "\r\n" ); message = readData(reader); if ( !message.startsWith("250") ) return false; // // // // 続きの処理(次回) // // // } catch (UnknownHostException e) { ret = false; } catch (IOException e) { ret = false; } catch (Exception e) { ret = false; } finally { try { reader.close(); writer.close(); connection.close(); } catch (IOException e2) { ret = false; } catch (Exception e2) { ret = false; } } return ret; } 次回は、この続き。メールアドレスなどを指定して実際に送信するところまでを書く予定。