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 * 1.Windows-31J + 8bit 送信
051 * 2.ISO-2022-JP に独自変換 + 7bit 送信
052 * の方法があります。
053 * 今回、この2つの方法について、対応いたしました。
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)。引数3つ追加(将来的には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                                @Override
171                                protected PasswordAuthentication getPasswordAuthentication() {
172                                        return new PasswordAuthentication( authUser,authPass );
173                                }
174                        };
175                }
176
177                // 6.3.8.0 (2015/09/11) SSL接続するかどうかを指定するパラメータを追加します。
178                // 5.9.29.2 (2018/02/16) STARTTLS対応  (キーワードをVer5 にあわせます)
179//              if( useSSL ) {
180                if ( useStarttls || useSSL ) {
181                        prop.setProperty("mail.smtp.starttls.enable"            , "true" );                                                     // 6.3.8.0 (2015/09/11)
182                        prop.setProperty("mail.smtp.starttls.required"          , "true" );                                                     // 6.3.8.0 (2015/09/11)
183                //      prop.setProperty("mail.smtp.socketFactory.class"        , "javax.net.ssl.SSLSocketFactory" );
184                //      prop.setProperty("mail.smtp.socketFactory.fallback"     , "false" );
185                //      prop.setProperty("mail.smtp.socketFactory.port"         , String.valueOf( smtpPort ) );         // 587
186                //      prop.setProperty("mail.transport.protocol"                      , "smtps" );    // 6.3.8.0 (2015/09/11)
187                }
188
189                // 6.9.1.0 (2018/02/26) STL/SSL 両対応
190                if ( useSSL ) {
191                        prop.setProperty("mail.smtp.socketFactory.class"        , "javax.net.ssl.SSLSocketFactory" );
192                        prop.setProperty("mail.smtp.socketFactory.fallback"     , "false" );
193                        prop.setProperty("mail.smtp.socketFactory.port"         , String.valueOf( smtpPort ) );         // 465
194                        prop.setProperty("mail.transport.protocol"                      , "smtps" );    // 6.3.8.0 (2015/09/11)
195                }
196
197                session = Session.getInstance( prop, myAuth );          // 6.2.4.1 (2015/05/22) SMTP_AUTH 対応
198
199                // POP before SMTP認証処理 5.4.3.2
200                if( AUTH_PBS.equals( authType ) ){
201                        try{
202                                // 5.8.1.1 (2014/11/14) 認証ポート追加
203                                final int aPort = authPort == null || authPort.isEmpty() || authPass == null || authPass.isEmpty() ? -1 : Integer.parseInt(authPort) ;
204                                final Store store = session.getStore("pop3");
205                                store.connect( host,aPort,authUser,authPass );  // 5.8.1.1 (2014/11/14) 認証ポート追加
206                                store.close();
207                        }
208                        catch( final MessagingException ex ) {
209                                final String errMsg = "POP3 Auth Exception: "+ host + "/" + authUser;
210                                throw new OgRuntimeException( errMsg,ex );
211                        }
212                }
213
214                mimeMsg = new MimeMessage( session );
215        }
216
217        /**
218         * メールを送信します。
219         *
220         */
221        public void sendmail() {
222                try {
223                        mimeMsg.setSentDate( new Date() );
224
225                        if( filename == null || filename.length == 0 ) {
226                                mcSet.setTextContent( mimeMsg,message );
227                        }
228                        else {
229                                mmPart = new MimeMultipart();
230                                mimeMsg.setContent( mmPart );
231                                // テキスト本体の登録
232                                addMmpText( message );
233
234                                // 添付ファイルの登録
235                                for( int i=0; i<filename.length; i++ ) {
236                                        addMmpFile( filename[i] );
237                                }
238                        }
239
240                        mimeMsg.setHeader("X-Mailer", MAILER );
241                        mimeMsg.setHeader("Content-Transfer-Encoding", mcSet.getBit() );
242                        Transport.send( mimeMsg );
243                }
244                catch( final AddressException ex ) {
245                        final String errMsg = "Address Exception: " + ex.getMessage() ;
246                        throw new OgRuntimeException( errMsg,ex );
247                }
248                catch( final MessagingException mex ) {
249                        final String errMsg = "MessagingException: " + mex.getMessage() ;
250                        throw new OgRuntimeException( errMsg,mex );
251                }
252        }
253
254        /**
255         * MimeMessageをリセットします。
256         *
257         * sendmail() でメールを送信後、セッションを閉じずに別のメールを送信する場合、
258         * リセットしてから、各種パラメータを再設定してください。
259         * その場合は、すべてのパラメータが初期化されていますので、もう一度
260         * 設定しなおす必要があります。
261         *
262         */
263        public void reset() {
264                mimeMsg = new MimeMessage(session);
265        }
266
267        /**
268         * 送信元(FROM)アドレスをセットします。
269         *
270         * @param   from 送信元(FROM)アドレス
271         */
272        public void setFrom( final String from ) {
273                try {
274                        if( from != null ) {
275                                mimeMsg.setFrom( getAddress( from ) );
276                        }
277                } catch( final AddressException ex ) {
278                        final String errMsg = "Address Exception: " + ex.getMessage() ;
279                        throw new OgRuntimeException( errMsg,ex );
280                } catch( final MessagingException mex ) {
281                        final String errMsg = "MessagingException: " + mex.getMessage() ;
282                        throw new OgRuntimeException( errMsg,mex );
283                }
284        }
285
286        /**
287         * 送信先(TO)アドレス配列をセットします。
288         *
289         * @param   to 送信先(TO)アドレス配列(可変長引数)
290         */
291        public void setTo( final String... to ) {
292                try {
293                        if( to != null && to.length > 0 ) {             // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
294                                mimeMsg.setRecipients( Message.RecipientType.TO, getAddress( to ) );
295                        }
296                } catch( final AddressException ex ) {
297                        final String errMsg = "Address Exception: " + ex.getMessage() ;
298                        throw new OgRuntimeException( errMsg,ex );
299                } catch( final MessagingException mex ) {
300                        final String errMsg = "MessagingException: " + mex.getMessage() ;
301                        throw new OgRuntimeException( errMsg,mex );
302                }
303        }
304
305        /**
306         * 送信先(CC)アドレス配列をセットします。
307         *
308         * @param   cc 送信先(CC)アドレス配列(可変長引数)
309         */
310        public void setCc( final String... cc ) {
311                try {
312                        if( cc != null && cc.length > 0 ) {             // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
313                                mimeMsg.setRecipients( Message.RecipientType.CC, getAddress( cc ) );
314                        }
315                } catch( final AddressException ex ) {
316                        final String errMsg = "Address Exception: " + ex.getMessage() ;
317                        throw new OgRuntimeException( errMsg,ex );
318                } catch( final MessagingException mex ) {
319                        final String errMsg = "MessagingException: " + mex.getMessage() ;
320                        throw new OgRuntimeException( errMsg,mex );
321                }
322        }
323
324        /**
325         * 送信先(BCC)アドレス配列をセットします。
326         *
327         * @param   bcc 送信先(BCC)アドレス配列(可変長引数)
328         */
329        public void setBcc( final String... bcc ) {
330                try {
331                        if( bcc != null && bcc.length > 0 ) {           // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
332                                mimeMsg.setRecipients( Message.RecipientType.BCC, getAddress( bcc ) );
333                        }
334                } catch( final AddressException ex ) {
335                        final String errMsg = "Address Exception: " + ex.getMessage() ;
336                        throw new OgRuntimeException( errMsg,ex );
337                } catch( final MessagingException mex ) {
338                        final String errMsg = "MessagingException: " + mex.getMessage() ;
339                        throw new OgRuntimeException( errMsg,mex );
340                }
341        }
342
343        /**
344         * 送信先(TO)アドレス配列をクリアします。
345         * @og.rev 4.3.6.0 (2009/04/01) 新規追加
346         *
347         */
348        public void clearTo() {
349                try {
350                        mimeMsg.setRecipients( Message.RecipientType.TO, (InternetAddress[])null );
351                } catch( final IllegalWriteException ex ) {
352                        final String errMsg = "Address Exception: " + ex.getMessage() ;
353                        throw new OgRuntimeException( errMsg,ex );
354                } catch( final IllegalStateException ex ) {
355                        final String errMsg = "Address Exception: " + ex.getMessage() ;
356                        throw new OgRuntimeException( errMsg,ex );
357                } catch( final MessagingException mex ) {
358                        final String errMsg = "MessagingException: " + mex.getMessage() ;
359                        throw new OgRuntimeException( errMsg,mex );
360                }
361        }
362
363        /**
364         * 送信先(CC)アドレス配列をクリアします。
365         *
366         * @og.rev 4.3.6.0 (2009/04/01) 新規追加
367         */
368        public void clearCc() {
369                try {
370                        mimeMsg.setRecipients( Message.RecipientType.CC, (InternetAddress[])null );
371                } catch( final IllegalWriteException ex ) {
372                        final String errMsg = "Address Exception: " + ex.getMessage() ;
373                        throw new OgRuntimeException( errMsg,ex );
374                } catch( final IllegalStateException ex ) {
375                        final String errMsg = "Address Exception: " + ex.getMessage() ;
376                        throw new OgRuntimeException( errMsg,ex );
377                } catch( final MessagingException mex ) {
378                        final String errMsg = "MessagingException: " + mex.getMessage() ;
379                        throw new OgRuntimeException( errMsg,mex );
380                }
381        }
382
383        /**
384         * 送信先(BCC)アドレス配列をクリアします。
385         * @og.rev 4.3.6.0 (2009/04/01) 新規追加
386         *
387         */
388        public void clearBcc() {
389                try {
390                        mimeMsg.setRecipients( Message.RecipientType.BCC, (InternetAddress[])null );
391                } catch( final IllegalWriteException ex ) {
392                        final String errMsg = "Address Exception: " + ex.getMessage() ;
393                        throw new OgRuntimeException( errMsg,ex );
394                } catch( final IllegalStateException ex ) {
395                        final String errMsg = "Address Exception: " + ex.getMessage() ;
396                        throw new OgRuntimeException( errMsg,ex );
397                } catch( final MessagingException mex ) {
398                        final String errMsg = "MessagingException: " + mex.getMessage() ;
399                        throw new OgRuntimeException( errMsg,mex );
400                }
401        }
402
403        /**
404         * 返信元(replyTo)アドレス配列をセットします。
405         *
406         * @param   replyTo 返信元(replyTo)アドレス配列(可変長引数)
407         */
408        public void setReplyTo( final String... replyTo ) {
409                try {
410                        if( replyTo != null && replyTo.length > 0 ) {           // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
411                                mimeMsg.setReplyTo( getAddress( replyTo ) );
412                        }
413                } catch( final AddressException ex ) {
414                        final String errMsg = "Address Exception: " + ex.getMessage() ;
415                        throw new OgRuntimeException( errMsg,ex );
416                } catch( final MessagingException mex ) {
417                        final String errMsg = "MessagingException: " + mex.getMessage() ;
418                        throw new OgRuntimeException( errMsg,mex );
419                }
420        }
421
422        /**
423         * タイトルをセットします。
424         *
425         * @param   subject タイトル
426         */
427        public void setSubject( final String subject ) {
428                // Servlet からの読み込みは、iso8859_1 でエンコードされた文字が
429                // セットされるので、ユニコードに変更しておかないと文字化けする。
430                // JRun 3.0 では、問題なかったが、tomcat3.1 では問題がある。
431                try {
432                        if( subject != null ) {
433                                mimeMsg.setSubject( mcSet.encodeWord( subject ) );
434                        }
435                } catch( final AddressException ex ) {
436                        final String errMsg = "Address Exception: " + ex.getMessage() ;
437                        throw new OgRuntimeException( errMsg,ex );
438                } catch( final MessagingException mex ) {
439                        final String errMsg = "MessagingException: " + mex.getMessage() ;
440                        throw new OgRuntimeException( errMsg,mex );
441                }
442        }
443
444        /**
445         * 添付ファイル名配列をセットします。
446         *
447         * @param   fname 添付ファイル名配列(可変長引数)
448         */
449        public void setFilename( final String... fname ) {
450                if( fname != null && fname.length > 0 ) {               // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
451                        final int size = fname.length;
452                        filename = new String[size];
453                        System.arraycopy( fname,0,filename,0,size );
454                }
455        }
456
457        /**
458         * メッセージ(本文)をセットします。
459         *
460         * @param   msg メッセージ(本文)
461         */
462        public void setMessage( final String msg ) {
463                // なぜか、メッセージの最後は、<CR><LF>をセットしておく。
464
465                if( msg == null ) { message = CR; }
466                else {              message = msg + CR; }
467        }
468
469        /**
470         * デバッグ情報の表示を行うかどうかをセットします。
471         *
472         * @param   debug 表示有無[true/false]
473         */
474        public void setDebug( final boolean debug ) {
475            session.setDebug( debug );
476        }
477
478        /**
479         * 指定されたファイルをマルチパートに追加します。
480         *
481         * @param   fileStr マルチパートするファイル名
482         */
483        private void addMmpFile( final String fileStr ) {
484                try {
485                        final MimeBodyPart mbp = new MimeBodyPart();
486                        final FileDataSource fds = new FileDataSource(fileStr);
487                        mbp.setDataHandler(new DataHandler(fds));
488                        mbp.setFileName(MimeUtility.encodeText(fds.getName(), charset, "B"));
489                        mbp.setHeader("Content-Transfer-Encoding", "base64");
490                        mmPart.addBodyPart(mbp);
491                }
492                catch( final UnsupportedEncodingException ex ) {
493                        final String errMsg = "Multipart UnsupportedEncodingException: " + ex.getMessage() ;
494                        throw new OgRuntimeException( errMsg,ex );
495                }
496                catch( final MessagingException mex ) {
497                        final String errMsg = "MessagingException: " + mex.getMessage() ;
498                        throw new OgRuntimeException( errMsg,mex );
499                }
500        }
501
502        /**
503         * 指定された文字列をマルチパートに追加します。
504         *
505         * @param   textStr マルチパートする文字列
506         */
507        private void addMmpText( final String textStr ) {
508                try {
509                        final MimeBodyPart mbp = new MimeBodyPart();
510                        mbp.setText(textStr, charset);
511                        mbp.setHeader("Content-Transfer-Encoding", mcSet.getBit());
512                        mmPart.addBodyPart(mbp, 0);
513                }
514                catch( final MessagingException mex ) {
515                        final String errMsg = "MessagingException: " + mex.getMessage() ;
516                        throw new OgRuntimeException( errMsg,mex );
517                }
518        }
519
520        /**
521         * 文字エンコードを考慮した InternetAddress を作成します。
522         *
523         * @param   adrs オリジナルのアドレス文字列
524         *
525         * @return  文字エンコードを考慮した InternetAddress
526         */
527        private InternetAddress getAddress( final String adrs ) {
528                final InternetAddress rtnAdrs ;
529                final int sep = adrs.indexOf( '<' );
530                if( sep >= 0 ) {
531                        final String address  = adrs.substring( sep+1,adrs.indexOf( '>' ) ).trim();
532                        final String personal = adrs.substring( 0,sep ).trim();
533
534                        rtnAdrs = mcSet.getAddress( address,personal );
535                }
536                else {
537                        try {
538                                rtnAdrs = new InternetAddress( adrs );
539                        }
540                        catch( final AddressException ex ) {
541                                final String errMsg = "指定のアドレスをセットできません。"
542                                                                        + "adrs=" + adrs + " , msg=" + ex.getMessage() ;
543                                throw new OgRuntimeException( errMsg,ex );
544                        }
545                }
546
547                return rtnAdrs ;
548        }
549
550        /**
551         * 文字エンコードを考慮した InternetAddress を作成します。
552         * これは、アドレス文字配列から、InternetAddress 配列を作成する、
553         * コンビニエンスメソッドです。
554         * 処理そのものは、#getAddress( String ) をループしているだけです。
555         *
556         * @param   adrs アドレス文字配列(可変長引数)
557         *
558         * @return  文字エンコード後のInternetAddress配列
559         * @see     #getAddress( String )
560         */
561        private InternetAddress[] getAddress( final String... adrs ) {
562                InternetAddress[] rtnAdrs = new InternetAddress[adrs.length];
563                for( int i=0; i<adrs.length; i++ ) {
564                        rtnAdrs[i] = getAddress( adrs[i] );
565                }
566
567                return rtnAdrs ;
568        }
569
570//      /**
571//       * javax.mail.Authenticator クラスの名前付き static 内部クラス
572//       *
573//       * SMTP認証用クラスとして使用します。6.2.4.1 (2015/05/22)
574//       *
575//       * 名前付き static 内部クラスにリファクタリングします(findbugs)。
576//       *
577//       * @og.rev 6.3.9.0 (2015/11/06) 新規追加
578//       * @og.rev 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更。
579//       *
580//       * @return  Authenticatorオブジェクト
581//       * @see     javax.mail.Authenticator
582//       */
583//      private static final class MyAuthenticator extends Authenticator {
584//              private final String authUser ;                         // 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更。
585//              private final String authPass ;                         // 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更。
586//
587//              /**
588//               * ユーザ,パスワードを指定したコンストラクター。
589//               *
590//               * @og.rev 6.3.9.0 (2015/11/06) 新規追加
591//               * @og.rev 6.4.1.1 (2016/01/16) PMD refactoring. It is a good practice to call super() in a constructor
592//               *
593//               * @param       authUser        認証ユーザ
594//               * @param       authPass        認証パスワード
595//               */
596//              public MyAuthenticator( final String authUser, final String authPass ) {
597//                      super();
598//                      this.authUser = authUser;
599//                      this.authPass = authPass;
600//              }
601//
602//              /**
603//               * パスワード認証が必要な時に呼ばれます。
604//               *
605//               * @og.rev 6.3.9.0 (2015/11/06) 新規追加
606//               *
607//               * @return      PasswordAuthenticationオブジェクト
608//               */
609//              @Override
610//              protected PasswordAuthentication getPasswordAuthentication() {
611//                      return new PasswordAuthentication( authUser,authPass );
612//              }
613//      }
614
615        /**
616         * コマンドから実行できる、テスト用の main メソッドです。
617         *
618         * Usage: java org.opengion.fukurou.mail.MailTX &lt;from&gt; &lt;to&gt; &lt;host&gt; [&lt;file&gt; ....]
619         * で、複数の添付ファイルを送付することができます。
620         *
621         * @og.rev 6.3.6.0 (2015/08/16) System.arraycopy が使える箇所は、置き換えます。
622         *
623         * @param       args    コマンド引数配列
624         */
625        public static void main( final String[] args ) {
626                if( args.length < 3 ) {
627                        LogWriter.log("Usage: java org.opengion.fukurou.mail.MailTX <from> <to> <host> [<file> ....]");
628                        return ;
629                }
630
631                final String host  = args[2] ;
632                final String chset = "ISO-2022-JP" ;
633
634                final MailTX sender = new MailTX( host,chset );
635
636                sender.setFrom( args[0] );
637                final String[] to = { args[1] };
638                sender.setTo( to );
639
640                if( args.length > 3 ) {
641                        final String[] filename = new String[args.length-3];
642                        // 6.3.6.0 (2015/08/16) System.arraycopy が使える箇所は、置き換えます。
643                        System.arraycopy( args,3,filename,0,filename.length );          // 6.3.6.0 (2015/08/16)
644                        sender.setFilename( filename );
645                }
646
647                sender.setSubject( "メール送信テスト" );
648                final String msg = "これはテストメールです。" + CR
649                                                +       "うまく受信できましたか?" + CR;
650                sender.setMessage( msg );
651
652                sender.sendmail();
653        }
654}