/*
 * Copyright (c) 2009 The openGion Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.opengion.fukurou.mail;

import org.opengion.fukurou.system.OgRuntimeException ;		// 6.4.2.0 (2016/01/29)
import org.opengion.fukurou.system.LogWriter;
import static org.opengion.fukurou.system.HybsConst.CR;				// 6.1.0.0 (2014/12/26) refactoring

import java.io.UnsupportedEncodingException;
import java.util.Properties;
import java.util.Date;

import javax.activation.FileDataSource;
import javax.activation.DataHandler;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.AddressException;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeUtility;
import javax.mail.Authenticator;									// 6.2.4.1 (2015/05/22) SMTP_AUTH 対応
import javax.mail.PasswordAuthentication;							// 6.2.4.1 (2015/05/22) SMTP_AUTH 対応
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.Session;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.IllegalWriteException;

/**
 * MailTX は、SMTPプロトコルによるメール送信プログラムです。
 *
 * E-Mail で日本語を送信する場合、ISO-2022-JP(JISコード)化して、7bit で
 * エンコードして送信する必要がありますが、Windows系の特殊文字や、unicodeと
 * 文字のマッピングが異なる文字などが、文字化けします。
 * 対応方法としては、
 * １．Windows-31J + 8bit 送信
 * ２．ISO-2022-JP に独自変換 + 7bit 送信
 * の方法があります。
 * 今回、この２つの方法について、対応いたしました。
 *
 * ※ 6.3.8.0 (2015/09/11)
 *    useSSL属性=true に設定すると、protocolに、smtps を使用します。
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public class MailTX {
	private static final String AUTH_PBS   = "POP_BEFORE_SMTP";		// 5.4.3.2
	private static final String AUTH_SMTPA = "SMTP_AUTH";			// 6.2.4.1 (2015/05/22) SMTP_AUTH 対応

	/** メーラーの名称  {@value} */
//	public static final String MAILER = "Hayabusa Mail Ver 4.0";
	public static final String MAILER = "openGion Mail Ver 6.0";

	private final String	charset	 ;	// Windwos-31J , MS932 , UTF-8 , ISO-2022-JP
	private String[]		filename ;
	private String			message	 ;
	private Session			session	 ;
	private MimeMultipart	mmPart	 ;
	private MimeMessage		mimeMsg	 ;
	private MailCharset		mcSet	 ;

	/**
	 * メールサーバーとデフォルト文字エンコーディングを指定して、オブジェクトを構築します。
	 *
	 * デフォルト文字エンコーディングは、ISO-2022-JP です。
	 *
	 * @param	host	メールサーバー
	 * @throws	IllegalArgumentException 引数が null の場合。
	 */
	public MailTX( final String host ) {
		this( host,"ISO-2022-JP" );
	}

	/**
	 * メールサーバーとデフォルト文字エンコーディングを指定して、オブジェクトを構築します。
	 *
	 * 文字エンコーディングには、Windwos-31J , MS932 , UTF-8 , ISO-2022-JP を指定できます。
	 *
	 * @og.rev 5.4.3.2 (2012/01/06) 認証対応のため
	 * @og.rev 5.8.1.1 (2014/11/14) 認証ポート追加
	 * @og.rev 6.3.8.0 (2015/09/11) SSL接続するかどうかを指定するパラメータを追加します。
	 *
	 * @param	host	メールサーバー
	 * @param	charset	文字エンコーディング
	 * @throws	IllegalArgumentException 引数が null の場合。
	 */
	public MailTX( final String host , final String charset ) {
//		this( host,charset,null,null,null,null,null );
		this( host,charset,null,null,null,null,null,false );
	}

	/**
	 * メールサーバーと文字エンコーディングを指定して、オブジェクトを構築します。
	 * 認証を行う場合は認証方法を指定します。
	 *
	 * 文字エンコーディングには、Windwos-31J , MS932 , ISO-2022-JP を指定できます。
	 *
	 * @og.rev 5.1.9.0 (2010/08/01) mail.smtp.localhostの設定追加
	 * @og.rev 5.4.3.2 (2012/01/06) 認証対応(POP Before SMTP)。引数３つ追加(将来的にはAuthentication対応？)
	 * @og.rev 5.8.1.1 (2014/11/14) 認証ポート追加
	 * @og.rev 6.2.4.1 (2015/05/22) SMTP_AUTH 対応
	 * @og.rev 6.3.8.0 (2015/09/11) SSL接続するかどうかを指定するパラメータを追加します。
	 *
	 * @param	host		メールサーバー
	 * @param	charset		文字エンコーディング
	 * @param	smtpPort	SMTPポート
	 * @param	authType	認証方法(POP_BEFORE_SMTP , SMTP_AUTH)
	 * @param	authPort	認証ポート
	 * @param	authUser	認証ユーザ
	 * @param	authPass	認証パスワード
	 * @param	useSSL		SSL接続するかどうか
	 * @throws	IllegalArgumentException 引数が null の場合。
	 */
	public MailTX( final String host , final String charset, final String smtpPort
//				,final String authType, final String authPort, final String authUser, final String authPass) {
				,final String authType, final String authPort, final String authUser, final String authPass, final boolean useSSL) {
		if( host == null ) {
			final String errMsg = "host に null はセット出来ません。";
			throw new IllegalArgumentException( errMsg );
		}

		if( charset == null ) {
			final String errMsg = "charset に null はセット出来ません。";
			throw new IllegalArgumentException( errMsg );
		}

		this.charset = charset;

		mcSet = MailCharsetFactory.newInstance( charset );

		final Properties prop = new Properties();
		prop.setProperty("mail.mime.charset"			, charset );
		prop.setProperty("mail.mime.decodetext.strict"	, "false" );
		prop.setProperty("mail.mime.address.strict"		, "false" );
		prop.setProperty("mail.smtp.host"				, host );
		// 5.1.9.0 (2010/08/01) 設定追加
		prop.setProperty("mail.smtp.localhost"			, host );
		prop.setProperty("mail.host"					, host );	// MEssage-ID の設定に利用

		// 6.3.8.0 (2015/09/11) SSL接続するかどうかを指定するパラメータを追加します。
		if( useSSL ) {
			prop.setProperty("mail.smtp.socketFactory.class"	, "javax.net.ssl.SSLSocketFactory" );
			prop.setProperty("mail.smtp.starttls.enable"		, "true" );							// 6.3.8.0 (2015/09/11)
			prop.setProperty("mail.smtp.socketFactory.fallback"	, "false" );
			prop.setProperty("mail.smtp.socketFactory.port"		, String.valueOf( smtpPort ) );		// 465
			prop.setProperty("mail.transport.protocol"			, "smtps" );	// 6.3.8.0 (2015/09/11)
		}

		// 5.4.3.2 ポート追加
		if( smtpPort != null && smtpPort.length() > 0 ){
			prop.setProperty("mail.smtp.port"			, smtpPort);	// MEssage-ID の設定に利用
		}

		// 6.2.4.1 (2015/05/22) SMTP_AUTH 対応
		Authenticator myAuth = null;
		if( AUTH_SMTPA.equals( authType ) ) {
			prop.setProperty("mail.smtp.auth"			, "true" );
			prop.setProperty("mail.transport.protocol"	, "smtps" );	// 6.3.8.0 (2015/09/11)
			// 6.3.9.0 (2015/11/06) 名前付き static 内部クラスにリファクタリング(findbugs)
			myAuth = new MyAuthenticator( authUser,authPass );
//			myAuth = new Authenticator() {								// 6.2.4.1 (2015/05/22) SMTP認証用クラス
//				/** PasswordAuthentication を返します。 */
//				@Override
//				protected PasswordAuthentication getPasswordAuthentication() {
//					return new PasswordAuthentication( authUser,authPass );
//				}
//			};
		}
		session = Session.getInstance( prop, myAuth );		// 6.2.4.1 (2015/05/22) SMTP_AUTH 対応

		// POP before SMTP認証処理 5.4.3.2
		if( AUTH_PBS.equals( authType ) ){
			try{
				// 5.8.1.1 (2014/11/14) 認証ポート追加
				final int aPort = authPass == null || authPass.isEmpty() ? -1 : Integer.parseInt(authPort) ;
				final Store store = session.getStore("pop3");
				store.connect( host,aPort,authUser,authPass );	// 5.8.1.1 (2014/11/14) 認証ポート追加
				store.close();
			}
			catch(MessagingException ex){
				final String errMsg = "POP3 Auth Exception: "+ host + "/" + authUser;
				throw new OgRuntimeException( errMsg,ex );
			}
		}

		mimeMsg = new MimeMessage( session );
	}

	/**
	 * メールを送信します。
	 *
	 */
	public void sendmail() {
		try {
			mimeMsg.setSentDate( new Date() );

			if( filename == null || filename.length == 0 ) {
				mcSet.setTextContent( mimeMsg,message );
			}
			else {
				mmPart = new MimeMultipart();
				mimeMsg.setContent( mmPart );
				// テキスト本体の登録
				addMmpText( message );

				// 添付ファイルの登録
				for( int i=0; i<filename.length; i++ ) {
					addMmpFile( filename[i] );
				}
			}

			mimeMsg.setHeader("X-Mailer", MAILER );
			mimeMsg.setHeader("Content-Transfer-Encoding", mcSet.getBit() );
			Transport.send( mimeMsg );
		}
		catch( AddressException ex ) {
			final String errMsg = "Address Exception: " + ex.getMessage() ;
			throw new OgRuntimeException( errMsg,ex );
		}
		catch ( MessagingException mex ) {
			final String errMsg = "MessagingException: " + mex.getMessage() ;
			throw new OgRuntimeException( errMsg,mex );
		}
	}

	/**
	 * MimeMessageをリセットします。
	 *
	 * sendmail() でメールを送信後、セッションを閉じずに別のメールを送信する場合、
	 * リセットしてから、各種パラメータを再設定してください。
	 * その場合は、すべてのパラメータが初期化されていますので、もう一度
	 * 設定しなおす必要があります。
	 *
	 */
	public void reset() {
		mimeMsg = new MimeMessage(session);
	}

	/**
	 * 送信元(ＦＲＯＭ)アドレスをセットします。
	 *
	 * @param   from 送信元(ＦＲＯＭ)アドレス
	 */
	public void setFrom( final String from ) {
		try {
			if( from != null ) {
				mimeMsg.setFrom( getAddress( from ) );
			}
		} catch( AddressException ex ) {
			final String errMsg = "Address Exception: " + ex.getMessage() ;
			throw new OgRuntimeException( errMsg,ex );
		} catch ( MessagingException mex ) {
			final String errMsg = "MessagingException: " + mex.getMessage() ;
			throw new OgRuntimeException( errMsg,mex );
		}
	}

	/**
	 * 送信先(ＴＯ)アドレス配列をセットします。
	 *
	 * @param   to 送信先(ＴＯ)アドレス配列(可変長引数)
	 */
	public void setTo( final String... to ) {
		try {
			if( to != null && to.length > 0 ) {		// 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
				mimeMsg.setRecipients( Message.RecipientType.TO, getAddress( to ) );
			}
		} catch( AddressException ex ) {
			final String errMsg = "Address Exception: " + ex.getMessage() ;
			throw new OgRuntimeException( errMsg,ex );
		} catch ( MessagingException mex ) {
			final String errMsg = "MessagingException: " + mex.getMessage() ;
			throw new OgRuntimeException( errMsg,mex );
		}
	}

	/**
	 * 送信先(ＣＣ)アドレス配列をセットします。
	 *
	 * @param   cc 送信先(ＣＣ)アドレス配列(可変長引数)
	 */
	public void setCc( final String... cc ) {
		try {
			if( cc != null && cc.length > 0 ) {		// 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
				mimeMsg.setRecipients( Message.RecipientType.CC, getAddress( cc ) );
			}
		} catch( AddressException ex ) {
			final String errMsg = "Address Exception: " + ex.getMessage() ;
			throw new OgRuntimeException( errMsg,ex );
		} catch ( MessagingException mex ) {
			final String errMsg = "MessagingException: " + mex.getMessage() ;
			throw new OgRuntimeException( errMsg,mex );
		}
	}

	/**
	 * 送信先(ＢＣＣ)アドレス配列をセットします。
	 *
	 * @param   bcc 送信先(ＢＣＣ)アドレス配列(可変長引数)
	 */
	public void setBcc( final String... bcc ) {
		try {
			if( bcc != null && bcc.length > 0 ) {		// 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
				mimeMsg.setRecipients( Message.RecipientType.BCC, getAddress( bcc ) );
			}
		} catch( AddressException ex ) {
			final String errMsg = "Address Exception: " + ex.getMessage() ;
			throw new OgRuntimeException( errMsg,ex );
		} catch ( MessagingException mex ) {
			final String errMsg = "MessagingException: " + mex.getMessage() ;
			throw new OgRuntimeException( errMsg,mex );
		}
	}

	/**
	 * 送信先(ＴＯ)アドレス配列をクリアします。
	 * @og.rev 4.3.6.0 (2009/04/01) 新規追加
	 *
	 */
	public void clearTo() {
		try {
			mimeMsg.setRecipients( Message.RecipientType.TO, (InternetAddress[])null );
		} catch( IllegalWriteException ex ) {
			final String errMsg = "Address Exception: " + ex.getMessage() ;
			throw new OgRuntimeException( errMsg,ex );
		} catch( IllegalStateException ex ) {
			final String errMsg = "Address Exception: " + ex.getMessage() ;
			throw new OgRuntimeException( errMsg,ex );
		} catch ( MessagingException mex ) {
			final String errMsg = "MessagingException: " + mex.getMessage() ;
			throw new OgRuntimeException( errMsg,mex );
		}
	}

	/**
	 * 送信先(CC)アドレス配列をクリアします。
	 *
	 * @og.rev 4.3.6.0 (2009/04/01) 新規追加
	 */
	public void clearCc() {
		try {
			mimeMsg.setRecipients( Message.RecipientType.CC, (InternetAddress[])null );
		} catch( IllegalWriteException ex ) {
			final String errMsg = "Address Exception: " + ex.getMessage() ;
			throw new OgRuntimeException( errMsg,ex );
		} catch( IllegalStateException ex ) {
			final String errMsg = "Address Exception: " + ex.getMessage() ;
			throw new OgRuntimeException( errMsg,ex );
		} catch ( MessagingException mex ) {
			final String errMsg = "MessagingException: " + mex.getMessage() ;
			throw new OgRuntimeException( errMsg,mex );
		}
	}

	/**
	 * 送信先(BCC)アドレス配列をクリアします。
	 * @og.rev 4.3.6.0 (2009/04/01) 新規追加
	 *
	 */
	public void clearBcc() {
		try {
			mimeMsg.setRecipients( Message.RecipientType.BCC, (InternetAddress[])null );
		} catch( IllegalWriteException ex ) {
			final String errMsg = "Address Exception: " + ex.getMessage() ;
			throw new OgRuntimeException( errMsg,ex );
		} catch( IllegalStateException ex ) {
			final String errMsg = "Address Exception: " + ex.getMessage() ;
			throw new OgRuntimeException( errMsg,ex );
		} catch ( MessagingException mex ) {
			final String errMsg = "MessagingException: " + mex.getMessage() ;
			throw new OgRuntimeException( errMsg,mex );
		}
	}

	/**
	 * 返信元(replyTo)アドレス配列をセットします。
	 *
	 * @param   replyTo 返信元(replyTo)アドレス配列(可変長引数)
	 */
	public void setReplyTo( final String... replyTo ) {
		try {
			if( replyTo != null && replyTo.length > 0 ) {		// 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
				mimeMsg.setReplyTo( getAddress( replyTo ) );
			}
		} catch( AddressException ex ) {
			final String errMsg = "Address Exception: " + ex.getMessage() ;
			throw new OgRuntimeException( errMsg,ex );
		} catch ( MessagingException mex ) {
			final String errMsg = "MessagingException: " + mex.getMessage() ;
			throw new OgRuntimeException( errMsg,mex );
		}
	}

	/**
	 * タイトルをセットします。
	 *
	 * @param   subject タイトル
	 */
	public void setSubject( final String subject ) {
		// Servlet からの読み込みは、iso8859_1 でエンコードされた文字が
		// セットされるので、ユニコードに変更しておかないと文字化けする。
		// JRun 3.0 では、問題なかったが、tomcat3.1 では問題がある。
		try {
			if( subject != null ) {
				mimeMsg.setSubject( mcSet.encodeWord( subject ) );
			}
		} catch( AddressException ex ) {
			final String errMsg = "Address Exception: " + ex.getMessage() ;
			throw new OgRuntimeException( errMsg,ex );
		} catch ( MessagingException mex ) {
			final String errMsg = "MessagingException: " + mex.getMessage() ;
			throw new OgRuntimeException( errMsg,mex );
		}
	}

	/**
	 * 添付ファイル名配列をセットします。
	 *
	 * @param   fname 添付ファイル名配列(可変長引数)
	 */
	public void setFilename( final String... fname ) {
		if( fname != null && fname.length > 0 ) {		// 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
			final int size = fname.length;
			filename = new String[size];
			System.arraycopy( fname,0,filename,0,size );
		}
	}

	/**
	 * メッセージ(本文)をセットします。
	 *
	 * @param   msg メッセージ(本文)
	 */
	public void setMessage( final String msg ) {
		// なぜか、メッセージの最後は、<CR><LF>をセットしておく。

		if( msg == null ) { message = CR; }
		else {              message = msg + CR; }
	}

	/**
	 * デバッグ情報の表示を行うかどうかをセットします。
	 *
	 * @param   debug 表示有無[true/false]
	 */
	public void setDebug( final boolean debug ) {
	    session.setDebug( debug );
	}

	/**
	 * 指定されたファイルをマルチパートに追加します。
	 *
	 * @param   fileStr マルチパートするファイル名
	 */
	private void addMmpFile( final String fileStr ) {
		try {
			final MimeBodyPart mbp = new MimeBodyPart();
			final FileDataSource fds = new FileDataSource(fileStr);
			mbp.setDataHandler(new DataHandler(fds));
			mbp.setFileName(MimeUtility.encodeText(fds.getName(), charset, "B"));
			mbp.setHeader("Content-Transfer-Encoding", "base64");
			mmPart.addBodyPart(mbp);
		}
		catch( UnsupportedEncodingException ex ) {
			final String errMsg = "Multipart UnsupportedEncodingException: " + ex.getMessage() ;
			throw new OgRuntimeException( errMsg,ex );
		}
		catch ( MessagingException mex ) {
			final String errMsg = "MessagingException: " + mex.getMessage() ;
			throw new OgRuntimeException( errMsg,mex );
		}
	}

	/**
	 * 指定された文字列をマルチパートに追加します。
	 *
	 * @param   textStr マルチパートする文字列
	 */
	private void addMmpText( final String textStr ) {
		try {
			final MimeBodyPart mbp = new MimeBodyPart();
			mbp.setText(textStr, charset);
			mbp.setHeader("Content-Transfer-Encoding", mcSet.getBit());
			mmPart.addBodyPart(mbp, 0);
		}
		catch ( MessagingException mex ) {
			final String errMsg = "MessagingException: " + mex.getMessage() ;
			throw new OgRuntimeException( errMsg,mex );
		}
	}

	/**
	 * 文字エンコードを考慮した InternetAddress を作成します。
	 *
	 * @param   adrs オリジナルのアドレス文字列
	 *
	 * @return  文字エンコードを考慮した InternetAddress
	 */
	private InternetAddress getAddress( final String adrs ) {
		final InternetAddress rtnAdrs ;
		final int sep = adrs.indexOf( '<' );
		if( sep >= 0 ) {
			final String address  = adrs.substring( sep+1,adrs.indexOf( '>' ) ).trim();
			final String personal = adrs.substring( 0,sep ).trim();

			rtnAdrs = mcSet.getAddress( address,personal );
		}
		else {
			try {
				rtnAdrs = new InternetAddress( adrs );
			}
			catch( AddressException ex ) {
				final String errMsg = "指定のアドレスをセットできません。"
									+ "adrs=" + adrs + " , msg=" + ex.getMessage() ;
				throw new OgRuntimeException( errMsg,ex );
			}
		}

		return rtnAdrs ;
	}

	/**
	 * 文字エンコードを考慮した InternetAddress を作成します。
	 * これは、アドレス文字配列から、InternetAddress 配列を作成する、
	 * コンビニエンスメソッドです。
	 * 処理そのものは、#getAddress( String ) をループしているだけです。
	 *
	 * @param   adrs アドレス文字配列(可変長引数)
	 *
	 * @return  文字エンコード後のInternetAddress配列
	 * @see     #getAddress( String )
	 */
	private InternetAddress[] getAddress( final String... adrs ) {
		InternetAddress[] rtnAdrs = new InternetAddress[adrs.length];
		for( int i=0; i<adrs.length; i++ ) {
			rtnAdrs[i] = getAddress( adrs[i] );
		}

		return rtnAdrs ;
	}

	/**
	 * javax.mail.Authenticator クラスの名前付き static 内部クラス
	 *
	 * SMTP認証用クラスとして使用します。6.2.4.1 (2015/05/22)
	 *
	 * 名前付き static 内部クラスにリファクタリングします(findbugs)。
	 *
	 * @og.rev 6.3.9.0 (2015/11/06) 新規追加
	 * @og.rev 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更。
	 *
	 * @return  Authenticatorオブジェクト
	 * @see     javax.mail.Authenticator
	 */
	private static final class MyAuthenticator extends Authenticator {
		private final String authUser ;				// 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更。
		private final String authPass ;				// 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更。

		/**
		 * ユーザ,パスワードを指定したコンストラクター。
		 *
		 * @og.rev 6.3.9.0 (2015/11/06) 新規追加
		 *
		 * @param	authUser	認証ユーザ
		 * @param	authPass	認証パスワード
		 */
		public MyAuthenticator( final String authUser, final String authPass ) {
			super();		// 6.4.1.1 (2016/01/16) PMD refactoring. It is a good practice to call super() in a constructor
			this.authUser = authUser;
			this.authPass = authPass;
		}

		/**
		 * パスワード認証が必要な時に呼ばれます。
		 *
		 * @og.rev 6.3.9.0 (2015/11/06) 新規追加
		 *
		 * @return	PasswordAuthenticationオブジェクト
		 */
		@Override
		protected PasswordAuthentication getPasswordAuthentication() {
			return new PasswordAuthentication( authUser,authPass );
		}
	}

	/**
	 * コマンドから実行できる、テスト用の main メソッドです。
	 *
	 * Usage: java org.opengion.fukurou.mail.MailTX &lt;from&gt; &lt;to&gt; &lt;host&gt; [&lt;file&gt; ....]
	 * で、複数の添付ファイルを送付することができます。
	 *
	 * @og.rev 6.3.6.0 (2015/08/16) System.arraycopy が使える箇所は、置き換えます。
	 *
	 * @param	args	コマンド引数配列
	 */
	public static void main( final String[] args ) {
		if( args.length < 3 ) {
			LogWriter.log("Usage: java org.opengion.fukurou.mail.MailTX <from> <to> <host> [<file> ....]");
			return ;
		}

		final String host  = args[2] ;
		final String chset = "ISO-2022-JP" ;

		final MailTX sender = new MailTX( host,chset );

		sender.setFrom( args[0] );
		final String[] to = { args[1] };
		sender.setTo( to );

		if( args.length > 3 ) {
			final String[] filename = new String[args.length-3];
			// 6.3.6.0 (2015/08/16) System.arraycopy が使える箇所は、置き換えます。
//			for( int i=0; i<args.length-3; i++ ) {
//				filename[i] = args[i+3];
//			}
			System.arraycopy( args,3,filename,0,filename.length );		// 6.3.6.0 (2015/08/16)
			sender.setFilename( filename );
		}

		sender.setSubject( "メール送信テスト" );
		final String msg = "これはテストメールです。" + CR
						+	"うまく受信できましたか?" + CR;
		sender.setMessage( msg );

		sender.sendmail();
	}
}
