★ The Tsuchinoko News 2 (つちのこ通信2) ★

重要な話から、どうでもいいことまで。ほとんど役に立たないことを書き連ねています。

【PC】Android で Socketを使ったメール送信(3)

f:id:tsuchinoko118:20120923172634j:image:left:w240前回、SMTPへの接続と HELOコマンドのお話をした。connection(socket)という通信係と reader=耳 と writer=口があれば、接続して→命令して→回答をチェックしてと繰り返していけばよい。しかし1つのコマンドに対して1つの回答しかない、のであればそれだけでよいのだが、実際には、1つしか命令していないのに、大量の回答を早口でまくしたててきたりするのが SMTPサーバーだ。
接続時には、うまくいけば「220」の1行だけ回答がある。
しかし「HELO」に対しては、私はこういうものです、私はこういうもので、接続はこのようにしています、みたいに、ずらずらっと回答がある。
このため「reader で読む」だけでは最後まで読めず、あとの処理に支障がある。「readerで読む」「readerで読む」「readerで読む」を繰り返し、最後の行まで読み込まないと、あとが続かない。
(読み残しが出来てしまうと、今 readした回答が、今命令したものに対してなのか、さきほどの命令に対するものかがわからなくなってしまう)
f:id:tsuchinoko118:20120923172637j:image:right:w240そこで、read専用の関数を作成する。ついでに write関数も作成してしまおう。メインの処理からは、この関数を介して通信することにする。

「HELO」への回答は、うまくいけば「250」から始まる行が数行返される。この中には、あとで処理する予定の認証方法や、接続の状態などの情報が記載される。1行だけというのは、まずない。ただ、3ケタのコード番号の後ろに、続きがある場合は(次の行がある場合は)「-」がついてくるので、これで最後の行(すなわち3ケタのコードの後ろに「-」ではなく空白になっている行)までを ループ処理で読み込んであげれば、全部の回答を読むことができる。
f:id:tsuchinoko118:20120923172646j:image:right:w240
回答データには重要な話しがたくさん掲載されているのだが、最後の行のコードだけ見れば十分というお手軽処理でメール送信をしていくことにする。


通常通りに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;
}

次回は、この続き。メールアドレスなどを指定して実際に送信するところまでを書く予定。