    001/*
    002 * Copyright (c) 2009 The openGion Project.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *     http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    013 * either express or implied. See the License for the specific language
    014 * governing permissions and limitations under the License.
    015 */
    016package org.opengion.fukurou.mail;
    017
    018import org.opengion.fukurou.system.OgRuntimeException ;         // 6.4.2.0 (2016/01/29)
    019import org.opengion.fukurou.system.LogWriter;
    020import static org.opengion.fukurou.system.HybsConst.CR;                         // 6.1.0.0 (2014/12/26) refactoring
    021
    022import java.io.UnsupportedEncodingException;
    023import java.util.Properties;
    024import java.util.Date;
    025
    026import javax.activation.FileDataSource;
    027import javax.activation.DataHandler;
    028import javax.mail.internet.InternetAddress;
    029import javax.mail.internet.AddressException;
    030import javax.mail.internet.MimeMessage;
    031import javax.mail.internet.MimeMultipart;
    032import javax.mail.internet.MimeBodyPart;
    033import javax.mail.internet.MimeUtility;
    034import javax.mail.Authenticator;                                                                        // 6.2.4.1 (2015/05/22) SMTP_AUTH 対応
    035import javax.mail.PasswordAuthentication;                                                       // 6.2.4.1 (2015/05/22) SMTP_AUTH 対応
    036import javax.mail.Store;
    037import javax.mail.Transport;
    038import javax.mail.Session;
    039import javax.mail.Message;
    040import javax.mail.MessagingException;
    041import javax.mail.IllegalWriteException;
    042
    043/**
    044 * MailTX は、SMTPプロトコルによるメール送信プログラムです。
    045 *
    046 * E-Mail で日本語を送信する場合、ISO-2022-JP(JISコード)化して、7bit で
    047 * エンコードして送信する必要がありますが、Windows系の特殊文字や、unicodeと
    048 * 文字のマッピングが異なる文字などが、文字化けします。
    049 * 対応方法としては、
    050 * １．Windows-31J + 8bit 送信
    051 * ２．ISO-2022-JP に独自変換 + 7bit 送信
    052 * の方法があります。
    053 * 今回、この２つの方法について、対応いたしました。
    054 *
    055 * ※ 6.3.8.0 (2015/09/11)
    056 *    useSSL属性=true に設定すると、protocolに、smtps を使用します。
    057 *
    058 * @version  4.0
    059 * @author   Kazuhiko Hasegawa
    060 * @since    JDK5.0,
    061 */
    062public class MailTX {
    063        private static final String AUTH_PBS   = "POP_BEFORE_SMTP";             // 5.4.3.2
    064        private static final String AUTH_SMTPA = "SMTP_AUTH";                   // 6.2.4.1 (2015/05/22) SMTP_AUTH 対応
    065
    066        /** メーラーの名称  {@value} */
    067        public static final String MAILER = "openGion Mail Ver 6.0";
    068
    069        private final String    charset  ;      // Windwos-31J , MS932 , UTF-8 , ISO-2022-JP
    070        private String[]                filename ;
    071        private String                  message  ;
    072        private Session                 session  ;
    073        private MimeMultipart   mmPart   ;
    074        private MimeMessage             mimeMsg  ;
    075        private MailCharset             mcSet    ;
    076
    077        /**
    078         * メールサーバーとデフォルト文字エンコーディングを指定して、オブジェクトを構築します。
    079         *
    080         * デフォルト文字エンコーディングは、ISO-2022-JP です。
    081         *
    082         * @param       host    メールサーバー
    083         * @throws      IllegalArgumentException 引数が null の場合。
    084         */
    085        public MailTX( final String host ) {
    086                this( host,"ISO-2022-JP" );
    087        }
    088
    089        /**
    090         * メールサーバーとデフォルト文字エンコーディングを指定して、オブジェクトを構築します。
    091         *
    092         * 文字エンコーディングには、Windwos-31J , MS932 , UTF-8 , ISO-2022-JP を指定できます。
    093         *
    094         * @og.rev 5.4.3.2 (2012/01/06) 認証対応のため
    095         * @og.rev 5.8.1.1 (2014/11/14) 認証ポート追加
    096         * @og.rev 6.3.8.0 (2015/09/11) SSL接続するかどうかを指定するパラメータを追加します。
    097         *
    098         * @param       host    メールサーバー
    099         * @param       charset 文字エンコーディング
    100         * @throws      IllegalArgumentException 引数が null の場合。
    101         */
    102        public MailTX( final String host , final String charset ) {
    103//              this( host,charset,null,null,null,null,null,false );
    104                this( host,charset,null,null,null,null,null,false,false );              // TSL,SSL
    105        }
    106
    107        /**
    108         * メールサーバーと文字エンコーディングを指定して、オブジェクトを構築します。
    109         * 認証を行う場合は認証方法を指定します。
    110         *
    111         * 文字エンコーディングには、Windwos-31J , MS932 , ISO-2022-JP を指定できます。
    112         *
    113         * @og.rev 5.1.9.0 (2010/08/01) mail.smtp.localhostの設定追加
    114         * @og.rev 5.4.3.2 (2012/01/06) 認証対応(POP Before SMTP)。引数３つ追加(将来的にはAuthentication対応？)
    115         * @og.rev 5.8.1.1 (2014/11/14) 認証ポート追加
    116         * @og.rev 6.2.4.1 (2015/05/22) SMTP_AUTH 対応
    117         * @og.rev 6.3.8.0 (2015/09/11) SSL接続するかどうかを指定するパラメータを追加します。
    118         * @og.rev 5.9.29.2 (2018/02/16) STARTTLS対応(ｷｰﾜｰﾄﾞをVer5 にあわせます)
    119         *
    120         * @param       host            メールサーバー
    121         * @param       charset         文字エンコーディング
    122         * @param       smtpPort        SMTPポート
    123         * @param       authType        認証方法(POP_BEFORE_SMTP , SMTP_AUTH)
    124         * @param       authPort        認証ポート
    125         * @param       authUser        認証ユーザ
    126         * @param       authPass        認証パスワード
    127         * @param       useStarttls 暗号化通信設定（STARTTLS) 5.9.29.2
    128         * @param       useSSL          SSL接続するかどうか
    129         * @throws      IllegalArgumentException 引数が null の場合。
    130         */
    131        public MailTX( final String host , final String charset, final String smtpPort
    132//                              ,final String authType, final String authPort, final String authUser, final String authPass, final boolean useSSL) {
    133                                ,final String authType, final String authPort, final String authUser, final String authPass, final boolean useStarttls, final boolean useSSL ) {
    134                if( host == null ) {
    135                        final String errMsg = "host に null はセット出来ません。";
    136                        throw new IllegalArgumentException( errMsg );
    137                }
    138
    139                if( charset == null ) {
    140                        final String errMsg = "charset に null はセット出来ません。";
    141                        throw new IllegalArgumentException( errMsg );
    142                }
    143
    144                this.charset = charset;
    145
    146                mcSet = MailCharsetFactory.newInstance( charset );
    147
    148                final Properties prop = new Properties();
    149                prop.setProperty("mail.mime.charset"                    , charset );
    150                prop.setProperty("mail.mime.decodetext.strict"  , "false" );
    151                prop.setProperty("mail.mime.address.strict"             , "false" );
    152                prop.setProperty("mail.smtp.host"                               , host );
    153                // 5.1.9.0 (2010/08/01) 設定追加
    154                prop.setProperty("mail.smtp.localhost"                  , host );
    155                prop.setProperty("mail.host"                                    , host );       // MEssage-ID の設定に利用
    156
    157                // 5.4.3.2 ポート追加
    158                if( smtpPort != null && smtpPort.length() > 0 ){
    159                        prop.setProperty("mail.smtp.port"                       , smtpPort);    // MEssage-ID の設定に利用
    160                }
    161
    162                // 6.2.4.1 (2015/05/22) SMTP_AUTH 対応
    163                Authenticator myAuth = null;
    164                if( AUTH_SMTPA.equals( authType ) ) {
    165                        prop.setProperty("mail.smtp.auth"                       , "true" );
    166                        prop.setProperty("mail.transport.protocol"      , "smtps" );    // 6.3.8.0 (2015/09/11)
    167                        // 6.3.9.0 (2015/11/06) 名前付き static 内部クラスにリファクタリング(findbugs)
    168        //              myAuth = new MyAuthenticator( authUser,authPass );
    169                        myAuth = new Authenticator() {                                  // 5.8.7.1 (2015/05/22) SMTP認証用クラス
    170                                /**
    171                                 * パスワード認証が必要な時には呼ばれる。
    172                                 *
    173                                 * @return      PasswordAuthenticationオブジェクト
    174                                 */
    175                                @Override
    176                                protected PasswordAuthentication getPasswordAuthentication() {
    177                                        return new PasswordAuthentication( authUser,authPass );
    178                                }
    179                        };
    180                }
    181
    182                // 6.3.8.0 (2015/09/11) SSL接続するかどうかを指定するパラメータを追加します。
    183                // 5.9.29.2 (2018/02/16) STARTTLS対応  (ｷｰﾜｰﾄﾞをVer5 にあわせます)
    184//              if( useSSL ) {
    185                if ( useStarttls || useSSL ) {
    186                        prop.setProperty("mail.smtp.starttls.enable"            , "true" );                                                     // 6.3.8.0 (2015/09/11)
    187                        prop.setProperty("mail.smtp.starttls.required"          , "true" );                                                     // 6.3.8.0 (2015/09/11)
    188                //      prop.setProperty("mail.smtp.socketFactory.class"        , "javax.net.ssl.SSLSocketFactory" );
    189                //      prop.setProperty("mail.smtp.socketFactory.fallback"     , "false" );
    190                //      prop.setProperty("mail.smtp.socketFactory.port"         , String.valueOf( smtpPort ) );         // 587
    191                //      prop.setProperty("mail.transport.protocol"                      , "smtps" );    // 6.3.8.0 (2015/09/11)
    192                }
    193
    194                // 6.9.1.0 (2018/02/26) STL/SSL 両対応
    195                if ( useSSL ) {
    196                        prop.setProperty("mail.smtp.socketFactory.class"        , "javax.net.ssl.SSLSocketFactory" );
    197                        prop.setProperty("mail.smtp.socketFactory.fallback"     , "false" );
    198                        prop.setProperty("mail.smtp.socketFactory.port"         , String.valueOf( smtpPort ) );         // 465
    199                        prop.setProperty("mail.transport.protocol"                      , "smtps" );    // 6.3.8.0 (2015/09/11)
    200                }
    201
    202                session = Session.getInstance( prop, myAuth );          // 6.2.4.1 (2015/05/22) SMTP_AUTH 対応
    203
    204                // POP before SMTP認証処理 5.4.3.2
    205                if( AUTH_PBS.equals( authType ) ){
    206                        try{
    207                                // 5.8.1.1 (2014/11/14) 認証ポート追加
    208                                final int aPort = authPort == null || authPort.isEmpty() || authPass == null || authPass.isEmpty() ? -1 : Integer.parseInt(authPort) ;
    209                                final Store store = session.getStore("pop3");
    210                                store.connect( host,aPort,authUser,authPass );  // 5.8.1.1 (2014/11/14) 認証ポート追加
    211                                store.close();
    212                        }
    213                        catch( final MessagingException ex ) {
    214                                final String errMsg = "POP3 Auth Exception: "+ host + "/" + authUser;
    215                                throw new OgRuntimeException( errMsg,ex );
    216                        }
    217                }
    218
    219                mimeMsg = new MimeMessage( session );
    220        }
    221
    222        /**
    223         * メールを送信します。
    224         *
    225         */
    226        public void sendmail() {
    227                try {
    228                        mimeMsg.setSentDate( new Date() );
    229
    230                        if( filename == null || filename.length == 0 ) {
    231                                mcSet.setTextContent( mimeMsg,message );
    232                        }
    233                        else {
    234                                mmPart = new MimeMultipart();
    235                                mimeMsg.setContent( mmPart );
    236                                // テキスト本体の登録
    237                                addMmpText( message );
    238
    239                                // 添付ファイルの登録
    240                                for( int i=0; i<filename.length; i++ ) {
    241                                        addMmpFile( filename[i] );
    242                                }
    243                        }
    244
    245                        mimeMsg.setHeader("X-Mailer", MAILER );
    246                        mimeMsg.setHeader("Content-Transfer-Encoding", mcSet.getBit() );
    247                        Transport.send( mimeMsg );
    248                }
    249                catch( final AddressException ex ) {
    250                        final String errMsg = "Address Exception: " + ex.getMessage() ;
    251                        throw new OgRuntimeException( errMsg,ex );
    252                }
    253                catch( final MessagingException mex ) {
    254                        final String errMsg = "MessagingException: " + mex.getMessage() ;
    255                        throw new OgRuntimeException( errMsg,mex );
    256                }
    257        }
    258
    259        /**
    260         * MimeMessageをリセットします。
    261         *
    262         * sendmail() でメールを送信後、セッションを閉じずに別のメールを送信する場合、
    263         * リセットしてから、各種パラメータを再設定してください。
    264         * その場合は、すべてのパラメータが初期化されていますので、もう一度
    265         * 設定しなおす必要があります。
    266         *
    267         */
    268        public void reset() {
    269                mimeMsg = new MimeMessage(session);
    270        }
    271
    272        /**
    273         * 送信元(ＦＲＯＭ)アドレスをセットします。
    274         *
    275         * @param   from 送信元(ＦＲＯＭ)アドレス
    276         */
    277        public void setFrom( final String from ) {
    278                try {
    279                        if( from != null ) {
    280                                mimeMsg.setFrom( getAddress( from ) );
    281                        }
    282                } catch( final AddressException ex ) {
    283                        final String errMsg = "Address Exception: " + ex.getMessage() ;
    284                        throw new OgRuntimeException( errMsg,ex );
    285                } catch( final MessagingException mex ) {
    286                        final String errMsg = "MessagingException: " + mex.getMessage() ;
    287                        throw new OgRuntimeException( errMsg,mex );
    288                }
    289        }
    290
    291        /**
    292         * 送信先(ＴＯ)アドレス配列をセットします。
    293         *
    294         * @param   to 送信先(ＴＯ)アドレス配列(可変長引数)
    295         */
    296        public void setTo( final String... to ) {
    297                try {
    298                        if( to != null && to.length > 0 ) {             // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
    299                                mimeMsg.setRecipients( Message.RecipientType.TO, getAddress( to ) );
    300                        }
    301                } catch( final AddressException ex ) {
    302                        final String errMsg = "Address Exception: " + ex.getMessage() ;
    303                        throw new OgRuntimeException( errMsg,ex );
    304                } catch( final MessagingException mex ) {
    305                        final String errMsg = "MessagingException: " + mex.getMessage() ;
    306                        throw new OgRuntimeException( errMsg,mex );
    307                }
    308        }
    309
    310        /**
    311         * 送信先(ＣＣ)アドレス配列をセットします。
    312         *
    313         * @param   cc 送信先(ＣＣ)アドレス配列(可変長引数)
    314         */
    315        public void setCc( final String... cc ) {
    316                try {
    317                        if( cc != null && cc.length > 0 ) {             // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
    318                                mimeMsg.setRecipients( Message.RecipientType.CC, getAddress( cc ) );
    319                        }
    320                } catch( final AddressException ex ) {
    321                        final String errMsg = "Address Exception: " + ex.getMessage() ;
    322                        throw new OgRuntimeException( errMsg,ex );
    323                } catch( final MessagingException mex ) {
    324                        final String errMsg = "MessagingException: " + mex.getMessage() ;
    325                        throw new OgRuntimeException( errMsg,mex );
    326                }
    327        }
    328
    329        /**
    330         * 送信先(ＢＣＣ)アドレス配列をセットします。
    331         *
    332         * @param   bcc 送信先(ＢＣＣ)アドレス配列(可変長引数)
    333         */
    334        public void setBcc( final String... bcc ) {
    335                try {
    336                        if( bcc != null && bcc.length > 0 ) {           // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
    337                                mimeMsg.setRecipients( Message.RecipientType.BCC, getAddress( bcc ) );
    338                        }
    339                } catch( final AddressException ex ) {
    340                        final String errMsg = "Address Exception: " + ex.getMessage() ;
    341                        throw new OgRuntimeException( errMsg,ex );
    342                } catch( final MessagingException mex ) {
    343                        final String errMsg = "MessagingException: " + mex.getMessage() ;
    344                        throw new OgRuntimeException( errMsg,mex );
    345                }
    346        }
    347
    348        /**
    349         * 送信先(ＴＯ)アドレス配列をクリアします。
    350         * @og.rev 4.3.6.0 (2009/04/01) 新規追加
    351         *
    352         */
    353        public void clearTo() {
    354                try {
    355                        mimeMsg.setRecipients( Message.RecipientType.TO, (InternetAddress[])null );
    356                } catch( final IllegalWriteException ex ) {
    357                        final String errMsg = "Address Exception: " + ex.getMessage() ;
    358                        throw new OgRuntimeException( errMsg,ex );
    359                } catch( final IllegalStateException ex ) {
    360                        final String errMsg = "Address Exception: " + ex.getMessage() ;
    361                        throw new OgRuntimeException( errMsg,ex );
    362                } catch( final MessagingException mex ) {
    363                        final String errMsg = "MessagingException: " + mex.getMessage() ;
    364                        throw new OgRuntimeException( errMsg,mex );
    365                }
    366        }
    367
    368        /**
    369         * 送信先(CC)アドレス配列をクリアします。
    370         *
    371         * @og.rev 4.3.6.0 (2009/04/01) 新規追加
    372         */
    373        public void clearCc() {
    374                try {
    375                        mimeMsg.setRecipients( Message.RecipientType.CC, (InternetAddress[])null );
    376                } catch( final IllegalWriteException ex ) {
    377                        final String errMsg = "Address Exception: " + ex.getMessage() ;
    378                        throw new OgRuntimeException( errMsg,ex );
    379                } catch( final IllegalStateException ex ) {
    380                        final String errMsg = "Address Exception: " + ex.getMessage() ;
    381                        throw new OgRuntimeException( errMsg,ex );
    382                } catch( final MessagingException mex ) {
    383                        final String errMsg = "MessagingException: " + mex.getMessage() ;
    384                        throw new OgRuntimeException( errMsg,mex );
    385                }
    386        }
    387
    388        /**
    389         * 送信先(BCC)アドレス配列をクリアします。
    390         * @og.rev 4.3.6.0 (2009/04/01) 新規追加
    391         *
    392         */
    393        public void clearBcc() {
    394                try {
    395                        mimeMsg.setRecipients( Message.RecipientType.BCC, (InternetAddress[])null );
    396                } catch( final IllegalWriteException ex ) {
    397                        final String errMsg = "Address Exception: " + ex.getMessage() ;
    398                        throw new OgRuntimeException( errMsg,ex );
    399                } catch( final IllegalStateException ex ) {
    400                        final String errMsg = "Address Exception: " + ex.getMessage() ;
    401                        throw new OgRuntimeException( errMsg,ex );
    402                } catch( final MessagingException mex ) {
    403                        final String errMsg = "MessagingException: " + mex.getMessage() ;
    404                        throw new OgRuntimeException( errMsg,mex );
    405                }
    406        }
    407
    408        /**
    409         * 返信元(replyTo)アドレス配列をセットします。
    410         *
    411         * @param   replyTo 返信元(replyTo)アドレス配列(可変長引数)
    412         */
    413        public void setReplyTo( final String... replyTo ) {
    414                try {
    415                        if( replyTo != null && replyTo.length > 0 ) {           // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
    416                                mimeMsg.setReplyTo( getAddress( replyTo ) );
    417                        }
    418                } catch( final AddressException ex ) {
    419                        final String errMsg = "Address Exception: " + ex.getMessage() ;
    420                        throw new OgRuntimeException( errMsg,ex );
    421                } catch( final MessagingException mex ) {
    422                        final String errMsg = "MessagingException: " + mex.getMessage() ;
    423                        throw new OgRuntimeException( errMsg,mex );
    424                }
    425        }
    426
    427        /**
    428         * タイトルをセットします。
    429         *
    430         * @param   subject タイトル
    431         */
    432        public void setSubject( final String subject ) {
    433                // Servlet からの読み込みは、iso8859_1 でエンコードされた文字が
    434                // セットされるので、ユニコードに変更しておかないと文字化けする。
    435                // JRun 3.0 では、問題なかったが、tomcat3.1 では問題がある。
    436                try {
    437                        if( subject != null ) {
    438                                mimeMsg.setSubject( mcSet.encodeWord( subject ) );
    439                        }
    440                } catch( final AddressException ex ) {
    441                        final String errMsg = "Address Exception: " + ex.getMessage() ;
    442                        throw new OgRuntimeException( errMsg,ex );
    443                } catch( final MessagingException mex ) {
    444                        final String errMsg = "MessagingException: " + mex.getMessage() ;
    445                        throw new OgRuntimeException( errMsg,mex );
    446                }
    447        }
    448
    449        /**
    450         * 添付ファイル名配列をセットします。
    451         *
    452         * @param   fname 添付ファイル名配列(可変長引数)
    453         */
    454        public void setFilename( final String... fname ) {
    455                if( fname != null && fname.length > 0 ) {               // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
    456                        final int size = fname.length;
    457                        filename = new String[size];
    458                        System.arraycopy( fname,0,filename,0,size );
    459                }
    460        }
    461
    462        /**
    463         * メッセージ(本文)をセットします。
    464         *
    465         * @param   msg メッセージ(本文)
    466         */
    467        public void setMessage( final String msg ) {
    468                // なぜか、メッセージの最後は、<CR><LF>をセットしておく。
    469
    470                if( msg == null ) { message = CR; }
    471                else {              message = msg + CR; }
    472        }
    473
    474        /**
    475         * デバッグ情報の表示を行うかどうかをセットします。
    476         *
    477         * @param   debug 表示有無[true/false]
    478         */
    479        public void setDebug( final boolean debug ) {
    480            session.setDebug( debug );
    481        }
    482
    483        /**
    484         * 指定されたファイルをマルチパートに追加します。
    485         *
    486         * @param   fileStr マルチパートするファイル名
    487         */
    488        private void addMmpFile( final String fileStr ) {
    489                try {
    490                        final MimeBodyPart mbp = new MimeBodyPart();
    491                        final FileDataSource fds = new FileDataSource(fileStr);
    492                        mbp.setDataHandler(new DataHandler(fds));
    493                        mbp.setFileName(MimeUtility.encodeText(fds.getName(), charset, "B"));
    494                        mbp.setHeader("Content-Transfer-Encoding", "base64");
    495                        mmPart.addBodyPart(mbp);
    496                }
    497                catch( final UnsupportedEncodingException ex ) {
    498                        final String errMsg = "Multipart UnsupportedEncodingException: " + ex.getMessage() ;
    499                        throw new OgRuntimeException( errMsg,ex );
    500                }
    501                catch( final MessagingException mex ) {
    502                        final String errMsg = "MessagingException: " + mex.getMessage() ;
    503                        throw new OgRuntimeException( errMsg,mex );
    504                }
    505        }
    506
    507        /**
    508         * 指定された文字列をマルチパートに追加します。
    509         *
    510         * @param   textStr マルチパートする文字列
    511         */
    512        private void addMmpText( final String textStr ) {
    513                try {
    514                        final MimeBodyPart mbp = new MimeBodyPart();
    515                        mbp.setText(textStr, charset);
    516                        mbp.setHeader("Content-Transfer-Encoding", mcSet.getBit());
    517                        mmPart.addBodyPart(mbp, 0);
    518                }
    519                catch( final MessagingException mex ) {
    520                        final String errMsg = "MessagingException: " + mex.getMessage() ;
    521                        throw new OgRuntimeException( errMsg,mex );
    522                }
    523        }
    524
    525        /**
    526         * 文字エンコードを考慮した InternetAddress を作成します。
    527         *
    528         * @param   adrs オリジナルのアドレス文字列
    529         *
    530         * @return  文字エンコードを考慮した InternetAddress
    531         */
    532        private InternetAddress getAddress( final String adrs ) {
    533                final InternetAddress rtnAdrs ;
    534                final int sep = adrs.indexOf( '<' );
    535                if( sep >= 0 ) {
    536                        final String address  = adrs.substring( sep+1,adrs.indexOf( '>' ) ).trim();
    537                        final String personal = adrs.substring( 0,sep ).trim();
    538
    539                        rtnAdrs = mcSet.getAddress( address,personal );
    540                }
    541                else {
    542                        try {
    543                                rtnAdrs = new InternetAddress( adrs );
    544                        }
    545                        catch( final AddressException ex ) {
    546                                final String errMsg = "指定のアドレスをセットできません。"
    547                                                                        + "adrs=" + adrs + " , msg=" + ex.getMessage() ;
    548                                throw new OgRuntimeException( errMsg,ex );
    549                        }
    550                }
    551
    552                return rtnAdrs ;
    553        }
    554
    555        /**
    556         * 文字エンコードを考慮した InternetAddress を作成します。
    557         * これは、アドレス文字配列から、InternetAddress 配列を作成する、
    558         * コンビニエンスメソッドです。
    559         * 処理そのものは、#getAddress( String ) をループしているだけです。
    560         *
    561         * @param   adrs アドレス文字配列(可変長引数)
    562         *
    563         * @return  文字エンコード後のInternetAddress配列
    564         * @see     #getAddress( String )
    565         */
    566        private InternetAddress[] getAddress( final String... adrs ) {
    567                InternetAddress[] rtnAdrs = new InternetAddress[adrs.length];
    568                for( int i=0; i<adrs.length; i++ ) {
    569                        rtnAdrs[i] = getAddress( adrs[i] );
    570                }
    571
    572                return rtnAdrs ;
    573        }
    574
    575//      /**
    576//       * javax.mail.Authenticator クラスの名前付き static 内部クラス
    577//       *
    578//       * SMTP認証用クラスとして使用します。6.2.4.1 (2015/05/22)
    579//       *
    580//       * 名前付き static 内部クラスにリファクタリングします(findbugs)。
    581//       *
    582//       * @og.rev 6.3.9.0 (2015/11/06) 新規追加
    583//       * @og.rev 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更。
    584//       *
    585//       * @return  Authenticatorオブジェクト
    586//       * @see     javax.mail.Authenticator
    587//       */
    588//      private static final class MyAuthenticator extends Authenticator {
    589//              private final String authUser ;                         // 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更。
    590//              private final String authPass ;                         // 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更。
    591//
    592//              /**
    593//               * ユーザ,パスワードを指定したコンストラクター。
    594//               *
    595//               * @og.rev 6.3.9.0 (2015/11/06) 新規追加
    596//               * @og.rev 6.4.1.1 (2016/01/16) PMD refactoring. It is a good practice to call super() in a constructor
    597//               *
    598//               * @param       authUser        認証ユーザ
    599//               * @param       authPass        認証パスワード
    600//               */
    601//              public MyAuthenticator( final String authUser, final String authPass ) {
    602//                      super();
    603//                      this.authUser = authUser;
    604//                      this.authPass = authPass;
    605//              }
    606//
    607//              /**
    608//               * パスワード認証が必要な時に呼ばれます。
    609//               *
    610//               * @og.rev 6.3.9.0 (2015/11/06) 新規追加
    611//               *
    612//               * @return      PasswordAuthenticationオブジェクト
    613//               */
    614//              @Override
    615//              protected PasswordAuthentication getPasswordAuthentication() {
    616//                      return new PasswordAuthentication( authUser,authPass );
    617//              }
    618//      }
    619
    620        /**
    621         * コマンドから実行できる、テスト用の main メソッドです。
    622         *
    623         * Usage: java org.opengion.fukurou.mail.MailTX &lt;from&gt; &lt;to&gt; &lt;host&gt; [&lt;file&gt; ....]
    624         * で、複数の添付ファイルを送付することができます。
    625         *
    626         * @og.rev 6.3.6.0 (2015/08/16) System.arraycopy が使える箇所は、置き換えます。
    627         *
    628         * @param       args    コマンド引数配列
    629         */
    630        public static void main( final String[] args ) {
    631                if( args.length < 3 ) {
    632                        LogWriter.log("Usage: java org.opengion.fukurou.mail.MailTX <from> <to> <host> [<file> ....]");
    633                        return ;
    634                }
    635
    636                final String host  = args[2] ;
    637                final String chset = "ISO-2022-JP" ;
    638
    639                final MailTX sender = new MailTX( host,chset );
    640
    641                sender.setFrom( args[0] );
    642                final String[] to = { args[1] };
    643                sender.setTo( to );
    644
    645                if( args.length > 3 ) {
    646                        final String[] filename = new String[args.length-3];
    647                        // 6.3.6.0 (2015/08/16) System.arraycopy が使える箇所は、置き換えます。
    648                        System.arraycopy( args,3,filename,0,filename.length );          // 6.3.6.0 (2015/08/16)
    649                        sender.setFilename( filename );
    650                }
    651
    652                sender.setSubject( "メール送信テスト" );
    653                final String msg = "これはテストメールです。" + CR
    654                                                +       "うまく受信できましたか?" + CR;
    655                sender.setMessage( msg );
    656
    657                sender.sendmail();
    658        }
    659}