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.util.StringUtil ;
019import org.opengion.fukurou.util.HybsEntry ;
020import org.opengion.fukurou.util.Argument ;
021import org.opengion.fukurou.util.FileUtil ;                                                     // 6.4.5.2 (2016/05/06)
022import static org.opengion.fukurou.system.HybsConst.CR;                         // 6.3.8.0 (2015/09/11)
023
024import java.util.Map;
025import java.util.LinkedHashMap;
026
027import java.util.logging.Logger;
028import java.util.logging.Level;
029
030/**
031 * MailTransfer は、SMTPプロトコルによるメール送信プログラムです。
032 *
033 * 引数には、host,from,to,cc,bcc,replyTo,subject,message,charset,file,debug,help が指定できます。
034 * 引数のプロパテイのキー部は、大文字・小文字が厳格に適用されますので、正確に記述願います。
035 *
036 * Usage: java org.opengion.fukurou.fukurou.mail.MailTransfer
037 *        -host=メールサーバー(必須)
038 *        -from=送信元アドレス(必須)
039 *        -to=送信先アドレスをCSV形式で並べる(必須)
040 *        -port=送信サーバーのポートを指定(初期値:-1)
041 *        -useSSL=SSL接続するかどうか[true:する/false:しない]を指定(初期値:false:しない)
042 *        -auth=認証方式(POP_BEFORE_SMTP , SMTP_AUTH のみ対応)
043 *        -authPort=認証ポート(初期値:-1)
044 *        -user=メールを取得するログインユーザー
045 *        -passwd=メールを取得するログインパスワード
046 *        -cc=関係者アドレスをCSV形式で並べる
047 *        -bcc=隠し送信先アドレスをCSV形式で並べる
048 *        -replyTo=返信先アドレスをCSV形式で並べる
049 *        -subject=タイトル
050 *        -message=本文を格納しているファイルのアドレス
051 *        -msgEncode=本文を格納しているファイルの文字コード(初期値:java.nio.charset.Charset#defaultCharset())
052 *        -charset=メール送信時のキャラクタセット [ISO-2022-JP / Windows-31J]
053 *        -fileXX=添付ファイルのファイルパス( XX は複数登録時の添え字 )
054 *        -debug=メイラーのデバッグモードを指定します。[false / true]
055 *        -help=使用方法を出力して、終了します。
056 *        -{@XXXX}=YYYY  メッセージ本文の {@XXXX} 文字列を、YYYY 文字列に変換します。
057 *            {@ARG.XXX} 予約文字変換 上記引数を割り当てます。
058 *            {@DATE.XXX} 予約文字変換 SimpleDateFormat 形式の文字を変換します。(日付、時刻等)
059 *            {@ENV.XXX}  予約文字変換 システムプロパティーの文字を変換します。(java -Dkey=value オプション)
060 *
061 * E-Mail で日本語を送信する場合、ISO-2022-JP(JISコード)化して、7bit で
062 * エンコードして送信する必要がありますが、Windows系の特殊文字や、unicodeと
063 * 文字のマッピングが異なる文字などが、文字化けします。
064 * 対応方法としては、
065 * 1.Windows-31J + 8bit 送信
066 * 2.ISO-2022-JP に独自変換 + 7bit 送信
067 * の方法があります。
068 * 今回、この2つの方法について、charset で指定できます。
069 * 初期値は、ISO-2022-JP です。
070 *
071 * ※ 6.2.4.1 (2015/05/22) SMTP_AUTH 対応
072 *
073 * ※ 6.3.8.0 (2015/09/11)
074 *    useSSL属性=true に設定すると、protocolに、smtps を使用します。
075 *
076 * @version  4.0
077 * @author   Kazuhiko Hasegawa
078 * @since    JDK5.0,
079 */
080public class MailTransfer {
081        // 6.3.9.1 (2015/11/27) The Logger variable declaration does not contain the static and final modifiers(PMD)
082        private static final Logger LOGGER = Logger.getLogger( MailTransfer.class.getName() );                                                  // 6.8.1.0 (2017/07/14) クラス名を動的作成に変更
083
084        /** メール送信時のデフォルトキャラクタセット 「={@value}」 */
085        public static final String CHARSET = "ISO-2022-JP" ;
086
087        /** メイラーの初期デバッグモード 「={@value}」 */
088        public static final boolean DEBUG_MODE = false ;
089
090        private Argument argment;                                                                       // 6.3.8.0 (2015/09/11)
091
092        /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */
093        private static final Map<String,String> MUST_PROPARTY   ;       // 必須パラメータ                                      // 6.4.1.1 (2016/01/16) mustProparty   → MUST_PROPARTY   refactoring
094        /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */
095        private static final Map<String,String> USABLE_PROPARTY ;       // 整合性チェックパラメータ                 // 6.4.1.1 (2016/01/16) usableProparty → USABLE_PROPARTY refactoring
096
097        static {
098                MUST_PROPARTY = new LinkedHashMap<>();
099                MUST_PROPARTY.put( "host",      "メールサーバー(必須)" );
100                MUST_PROPARTY.put( "from",      "送信元アドレス(必須)" );
101                MUST_PROPARTY.put( "to",                "送信先アドレスをCSV形式で並べる(必須)" );
102
103                USABLE_PROPARTY = new LinkedHashMap<>();
104                USABLE_PROPARTY.put( "port"             , "送信サーバーのポート" );                                       // 6.0.3.0 (2014/11/13) SMTP認証
105                USABLE_PROPARTY.put( "useSSL"           , "SSL接続するかどうかを指定(初期値:false:しない)" );                    // 6.3.8.0 (2015/09/11)
106                USABLE_PROPARTY.put( "useStarttls"      , "STARTTLS接続するかどうかを指定(初期値:false:しない)" );               // 5.9.29.2 (2018/02/16)
107                USABLE_PROPARTY.put( "auth"             , "認証方式(POP_BEFORE_SMTP , SMTP_AUTHのみ対応)" );                    // 6.2.4.1 (2015/05/22)
108                USABLE_PROPARTY.put( "authPort" , "認証ポート" );                                                            // 6.0.3.0 (2014/11/13) SMTP認証
109                USABLE_PROPARTY.put( "user"             , "認証ユーザー" );                                                   // 6.0.3.0 (2014/11/13) SMTP認証
110                USABLE_PROPARTY.put( "passwd"   , "認証パスワード" );                                                  // 6.0.3.0 (2014/11/13) SMTP認証
111                USABLE_PROPARTY.put( "cc"               , "関係者アドレスをCSV形式で並べる" );
112                USABLE_PROPARTY.put( "bcc"              , "隠し送信先アドレスをCSV形式で並べる" );
113                USABLE_PROPARTY.put( "replyTo"  , "返信先アドレスをCSV形式で並べる" );
114                USABLE_PROPARTY.put( "subject"  , "タイトル" );
115                USABLE_PROPARTY.put( "message"  , "本文を格納しているファイルのアドレス" );
116                USABLE_PROPARTY.put( "msgEncode"        , "本文を格納しているファイルの文字コード [Windows-31J / UTF-8]" );
117                USABLE_PROPARTY.put( "charset"  , "メール送信時のキャラクタセット [ISO-2022-JP / Windows-31J]" );
118                USABLE_PROPARTY.put( "file"             , "添付ファイルのファイルパス( XX は複数登録時の添え字 )" );
119                USABLE_PROPARTY.put( "{@"               , "{@XXXX}=YYYY  メッセージ本文の {@XXXX} 文字列を、YYYY 文字列に変換します。" );
120                USABLE_PROPARTY.put( "{@ARG."   , "{@ARG.XXX} 予約文字変換 上記引数を割り当てます。" );
121                USABLE_PROPARTY.put( "{@DATE."  , "{@DATE.XXX} 予約文字変換 SimpleDateFormat 形式の文字を変換します。(日付、時刻等)" );
122                USABLE_PROPARTY.put( "{@ENV."   , "{@ENV.XXX} 予約文字変換 システムプロパティーの文字を変換します。(java -Dkey=value オプション)" );
123                USABLE_PROPARTY.put( "debug"            , "メイラーのデバッグモードを指定します。[false / true]" );
124                USABLE_PROPARTY.put( "help"             , "使用方法を出力して、終了します。" );
125        }
126
127        /**
128         * トランスファーを開始します。
129         *
130         * @og.rev 4.3.3.5 (2008/11/08) Argument オブジェクトへの引数を util → mail に訂正します。
131         * @og.rev 6.0.3.0 (2014/11/13) SMTP認証
132         * @og.rev 6.3.8.0 (2015/09/11) SSL接続するかどうかを指定するパラメータを追加します。
133         * @og.rev 6.3.8.0 (2015/09/11) message で指定されたファイルの
134         * @og.rev 6.4.5.1 (2016/04/28) FileStringのコンストラクター変更
135         * @og.rev 6.4.5.2 (2016/05/06) fukurou.util.FileString から、fukurou.util.FileUtil に移動。
136         * @og.rev 5.9.29.2 (2018/02/16) STARTTLS対応(キーワードをVer5 にあわせます)
137         *
138         * @param       args    引数配列(可変長引数)
139         */
140        public void start( final String... args ) {
141
142                // パラメータの解析、取得
143                LOGGER.fine( "パラメータの解析、取得" );
144                argment = new Argument( "org.opengion.fukurou.mail.MailTransfer" );             // 4.3.3.5 (2008/11/08)
145                argment.setMustProparty( MUST_PROPARTY );
146                argment.setUsableProparty( USABLE_PROPARTY );
147
148                argment.setArgument( args );
149
150                // help パラメータが true に指定された場合の処理。
151                if( argment.getProparty( "help",false ) ) {
152                        System.out.println( argment.toString() );
153                        return;
154                }
155
156                final String host               = argment.getProparty( "host" );
157                final String chset              = argment.getProparty( "charset", CHARSET );
158
159                final boolean useSSL            = argment.getProparty( "useSSL"                 ,false );               // 6.3.8.0 (2015/09/11) SSL接続
160                final boolean useStarttls       = argment.getProparty( "useStarttls"    ,false );               // 5.9.29.2 (2018/02/16) 
161
162                final String port               = argment.getProparty( "port" );                                // 6.0.3.0 (2014/11/13) SMTP認証
163                final String auth               = argment.getProparty( "auth" );                                // 6.0.3.0 (2014/11/13) SMTP認証
164                final String authPort   = argment.getProparty( "authPort" );                    // 6.0.3.0 (2014/11/13) SMTP認証
165                final String user               = argment.getProparty( "user" );                                // 6.0.3.0 (2014/11/13) SMTP認証
166                final String passwd             = argment.getProparty( "passwd" );                              // 6.0.3.0 (2014/11/13) SMTP認証
167
168//              final MailTX mail = new MailTX( host,chset,port,auth,authPort,user,passwd,useSSL );                             // 6.3.8.0 (2015/09/11) SSL接続
169                final MailTX mail = new MailTX( host,chset,port,auth,authPort,user,passwd,useStarttls,useSSL ); // 6.3.8.0 (2015/09/11) SSL接続
170                LOGGER.fine( "org.opengion.fukurou.mail.MailTX の設定" );
171
172                mail.setFrom(                                                   argment.getProparty( "from" ) );
173                mail.setTo(              StringUtil.csv2Array(  argment.getProparty( "to" ) ) );
174                mail.setCc(              StringUtil.csv2Array(  argment.getProparty( "cc" ) ) );
175                mail.setBcc(     StringUtil.csv2Array(  argment.getProparty( "bcc" ) ) );
176                mail.setReplyTo( StringUtil.csv2Array(  argment.getProparty( "replyTo" ) ) );
177                mail.setSubject(                                                argment.getProparty( "subject" ) );
178                mail.setDebug(                                                  argment.getProparty( "debug", DEBUG_MODE ) );
179
180                // message は、本文を格納しているファイル名が指定されています。
181                final String msgFile   = argment.getProparty( "message" ) ;
182                LOGGER.fine( "本文を格納しているファイルの取得。message=" + msgFile );
183                if( msgFile != null ) {
184                        final String msgEncode = argment.getProparty( "msgEncode" ) ;
185                        // 6.4.5.1 (2016/04/28) FileStringのコンストラクター変更
186                        String message = FileUtil.getValue( msgFile , msgEncode );      // 6.4.5.2 (2016/05/06)
187
188                        // {@XXX} 変換は、Argument クラスの機能を使う。
189                        message = argment.changeParam( message );
190                        mail.setMessage( message );
191                }
192
193                // 添付ファイルは、fileXX 形式で、複数指定されています。
194                LOGGER.fine( "添付ファイルを取り込みます。" );
195                final HybsEntry[] entry = argment.getEntrys( "file" );
196                String[] files = new String[entry.length];
197                for( int i=0; i<files.length; i++ ) {
198                        files[i] = entry[i].getValue() ;
199                }
200                mail.setFilename( files );
201
202                // 送信
203                LOGGER.fine( "送信処理を行います。" );
204                mail.sendmail();
205        }
206
207        /**
208         * main メソッドです。
209         *
210         * @param       args    引数配列
211         */
212        public static void main ( final String[] args ) {
213                final MailTransfer transfer = new MailTransfer();
214                try {
215                        LOGGER.info( "メール送信処理を開始します  ---------------------------------------------" );
216                        transfer.start( args );
217                        LOGGER.info( "正常に終了しました。" );
218                }
219                catch( final Throwable th ) {
220                        final String errMsg = "メール送信中に例外が発生しました。 "
221                                                        + CR + transfer.argment
222                                                        + CR + th.getMessage() ;
223                        LOGGER.log( Level.SEVERE,errMsg, th );
224                }
225        }
226}