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 java.util.Map; 019import java.util.LinkedHashMap; 020import java.util.logging.Logger; 021import java.util.logging.Level; 022 023import jakarta.mail.MessagingException ; 024 025import org.opengion.fukurou.util.HybsEntry ; 026import org.opengion.fukurou.util.Argument ; 027import static org.opengion.fukurou.system.HybsConst.CR; // 6.1.0.0 (2014/12/26) refactoring 028 029/** 030 * MailReceiver は、POP3/IMAPプロトコルによるメール受信プログラムです。 031 * 032 * 引数には、host,user,passwd などが指定できます。 033 * メールは、メッセージID名をファイル名として、セーブします。 034 * 添付ファイルは、元のファイル名で、指定のディレクトリに出力される為、複数のメールを 035 * 同時に抜く場合は、uniq 属性を付与してください。その場合は、メッセージID+連番+元のファイル名 036 * で、ファイルをセーブします。添付ファイルには、同名のファイルを複数添付することが 037 * できるため、保存時には、添付ファイルの番号を連番としてファイル名に、付与します。 038 * 039 * 引数のプロパテイのキー部は、大文字・小文字が厳格に適用されますので、正確に記述願います。 040 * 041 * Usage: java org.opengion.fukurou.fukurou.mail.MailReceiver 042 * -host=メールサーバー(必須) 043 * -user=メールを取得するログインユーザー(必須) 044 * -passwd=メールを取得するログインパスワード(必須) 045 * -protocol=受信サーバーのプロトコル[imap/pop3]を指定(初期値:{@og.value #PROTOCOL}) 046 * -port=受信サーバーのポートを指定(初期値:{@og.value #PORT}) 047 * -useSSL=SSL接続するかどうか[true:する/false:しない]を指定(初期値:false:しない) 048 * -mailSaveDir=受信メールをセーブするディレクトリ。指定がない場合は、標準出力へ出力する。 049 * -fileSaveDir=添付ファイルをセーブするディレクトリ。指定がない場合は抜き出さない。 050 * -useMsgId=添付ファイルをセーブするディレクトリに、MesssageIdフォルダを個別に割り当てるかどうか(初期値:false) 051 * -maxRowCount=受信メールの最大取り込み件数(初期値:{@og.value #MAX_ROW_COUNT})(0:[無制限]) 052 * -match_Subject=受信メールのSubjectを選択する条件 053 * -match_Body=受信メールのBodyを選択する条件 054 * -match_From=受信メールのFromを選択する条件 055 * -match_XXXX=受信メールのヘッダー部のキーXXXXを選択する条件 056 * -delete=検索後、メールをサーバーから削除するかどうかを、true/falseで指定(初期値:false) 057 * -help=使用方法を出力して、終了します。 058 * 059 * ※ 6.3.8.0 (2015/09/11) 060 * useSSL属性は、protocolに、pop3s/imaps を指定した場合、 061 * 自動的に、ture に設定するようにしています。 062 * 063 * @version 0.9.0 2000/11/13 064 * @author Kazuhiko Hasegawa 065 * @since JDK5.0, 066 */ 067public class MailReceiver { 068 // 6.3.9.1 (2015/11/27) The Logger variable declaration does not contain the static and final modifiers(PMD) 069 /** 6.8.1.0 (2017/07/14) クラス名を動的作成に変更 */ 070 private static final Logger LOGGER = Logger.getLogger( MailReceiver.class.getName() ); 071 072 /** 受信メールの最大取り込み件数を指定します 「={@value}」 */ 073 public static final int MAX_ROW_COUNT = 100 ; 074 075 /** 検索後、メールをサーバーから削除するかどうかを、true/falseで指定します 「={@value}」 */ 076 public static final boolean DELETE_MESSAGE = false ; 077 078 /** メールサーバーのデフォルトプロトコル 「={@value}」 */ 079 public static final String PROTOCOL = "pop3" ; 080 081 /** メールサーバーのデフォルトポート番号 「={@value}」 */ 082 public static final int PORT = -1 ; 083 084 private Argument argment ; 085 086 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */ 087 private static final Map<String,String> MUST_PROPARTY ; // 6.4.1.1 (2016/01/16) mustProparty → MUST_PROPARTY refactoring 088 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */ 089 private static final Map<String,String> USABLE_PROPARTY ; // 6.4.1.1 (2016/01/16) usableProparty → USABLE_PROPARTY refactoring 090 091 static { 092 MUST_PROPARTY = new LinkedHashMap<>(); 093 MUST_PROPARTY.put( "host" , "メールサーバー(必須)" ); 094 MUST_PROPARTY.put( "user" , "メールを取得するログインユーザー(必須)" ); 095 MUST_PROPARTY.put( "passwd" , "メールを取得するログインパスワード(必須)" ); 096 097 USABLE_PROPARTY = new LinkedHashMap<>(); 098 USABLE_PROPARTY.put( "protocol" , "受信サーバーのプロトコル(imap,pop3)を指定(初期値:pop3)" ); 099 USABLE_PROPARTY.put( "port" , "受信サーバーのポートを指定(初期値:-1)" ); 100 USABLE_PROPARTY.put( "useSSL" , "SSL接続するかどうかを指定(初期値:false:しない)" ); // 6.3.8.0 (2015/09/11) 101 USABLE_PROPARTY.put( "mailSaveDir" , "受信メールをセーブするディレクトリ。" + 102 CR + "指定がない場合は、標準出力へ出力する。" ); 103 USABLE_PROPARTY.put( "fileSaveDir" , "添付ファイルをセーブするディレクトリ。" + 104 CR + "指定がない場合は抜き出さない。" ); 105 USABLE_PROPARTY.put( "useMsgId" , "添付ファイルをセーブするディレクトリに、" + 106 CR + "MesssageIdフォルダを個別に割り当てるかどうか。" ); 107 USABLE_PROPARTY.put( "maxRowCount" , "受信メールの最大取り込み件数(初期値:100)(0:[無制限])" ); 108 USABLE_PROPARTY.put( "match_Subject" , "受信メールのSubjectを選択する条件" ); 109 USABLE_PROPARTY.put( "match_Body" , "受信メールのBodyを選択する条件" ); 110 USABLE_PROPARTY.put( "match_From" , "受信メールのFromを選択する条件" ); 111 USABLE_PROPARTY.put( "match_" , "受信メールのヘッダー部のキーXXXXを選択する条件" ); 112 USABLE_PROPARTY.put( "delete" , "検索後、メールをサーバーから削除するかどうかを、" + 113 CR + "true/falseで指定(初期値:false)" ); 114 USABLE_PROPARTY.put( "help" , "使用方法を出力して、終了します。" ); 115 } 116 117 /** 118 * デフォルトコンストラクター 119 * 120 * @og.rev 8.5.3.2 (2023/10/13) JDK21対応。警告: デフォルトのコンストラクタの使用で、コメントが指定されていません 121 */ 122 public MailReceiver() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 123 124 /** 125 * レシーバーを開始します。 126 * 127 * @og.rev 4.3.3.5 (2008/11/08) Argument オブジェクトへの引数を util → mail に訂正します。 128 * @og.rev 6.3.8.0 (2015/09/11) SSL接続するかどうかを指定するパラメータを追加します。 129 * 130 * @param args 引数配列(可変長引数) 131 * @throws MessagingException なんらかのエラーが発生した場合。 132 */ 133 public void start( final String... args ) throws MessagingException { 134 135 // パラメータの解析、取得 136 LOGGER.fine( "パラメータの解析、取得" ); 137 argment = new Argument( "org.opengion.fukurou.fukurou.mail.MailReceiver" ); // 4.3.3.5 (2008/11/08) 138 argment.setMustProparty( MUST_PROPARTY ); 139 argment.setUsableProparty( USABLE_PROPARTY ); 140 141 argment.setArgument( args ); 142 143 // help パラメータが true に指定された場合の処理。 144 if( argment.getProparty( "help",false ) ) { 145 System.out.println( argment.toString() ); 146 return; 147 } 148 149 // 処理に必要な各種パラメータを取得しておきます。 150 LOGGER.fine( "処理に必要な各種パラメータを取得します。" ); 151 final MailRX recive = new MailRX(); 152 153 recive.setHost( argment.getProparty( "host" ) ) ; 154 recive.setUser( argment.getProparty( "user" ) ) ; 155 recive.setPasswd( argment.getProparty( "passwd" ) ) ; 156 recive.setProtocol( argment.getProparty( "protocol" ,PROTOCOL ) ) ; 157 recive.setPort( argment.getProparty( "port" ,PORT ) ) ; 158 recive.useSSL( argment.getProparty( "useSSL" ,false ) ) ; // 6.3.8.0 (2015/09/11) 159 recive.setDelete( argment.getProparty( "delete" ,DELETE_MESSAGE ) ) ; 160 recive.setMaxRowCount( argment.getProparty( "maxRowCount",MAX_ROW_COUNT ) ) ; 161 162 // 指定の条件にマッチしたメッセージのみ抜き出す為の、SearchTerm オブジェクトの作成 163 LOGGER.fine( "指定の条件にマッチしたメッセージのみ抜き出す条件を設定します。" ); 164 // 8.5.4.2 (2024/01/12) PMD 7.0.0 ForLoopCanBeForeach 165// final HybsEntry[] matchs = argment.getEntrys( "match_" ); 166// for( int i=0; i<matchs.length; i++ ) { 167// recive.addMatchTerm( matchs[i] ) ; 168// } 169 for( final HybsEntry match : argment.getEntrys( "match_" ) ) { 170 recive.addMatchTerm( match ) ; 171 } 172 173 // リスナーを設定して、受信メールを一件ずつ処理します。 174 LOGGER.fine( "リスナーを設定して、受信メールを一件ずつ処理します。" ); 175 final String mailSaveDir = argment.getProparty( "mailSaveDir" ); 176 final String fileSaveDir = argment.getProparty( "fileSaveDir" ); 177 final boolean useMsgId = argment.getProparty( "useMsgId",false ); 178 179 final MailReceiveListener listener = new ReceiveListener( mailSaveDir,fileSaveDir,useMsgId ) ; 180 recive.setMailReceiveListener( listener ); 181 182 recive.start(); 183 } 184 185 /** 186 * メール受信プログラムで使用する MailReceiveListener の実装内部クラスです。 187 * 188 * @version 0.9.0 2000/11/13 189 * @author Kazuhiko Hasegawa 190 * @since JDK5.0, 191 */ 192 private static final class ReceiveListener implements MailReceiveListener { 193 private final String mailSaveDir ; 194 private final String fileSaveDir ; 195 private final boolean useMsgId ; 196 private int counter ; 197 198 /** 199 * コンストラクター 200 * 201 * @param mailSaveDir メールをセーブする場合の保存フォルダ名 202 * @param fileSaveDir メールの添付ファイルをセーブする場合の保存フォルダ名 203 * @param useMsgId 添付ファイルをセーブする場合に、メッセージIDを使用するかどうか 204 */ 205 public ReceiveListener( final String mailSaveDir,final String fileSaveDir,final boolean useMsgId ) { 206 this.mailSaveDir = mailSaveDir; 207 this.fileSaveDir = fileSaveDir; 208 this.useMsgId = useMsgId; 209 } 210 211 /** 212 * 受信処理を行います。 213 * 214 * @param message MailMessageオブジェクト 215 * @return 結果(true:正常/false:異常) 216 */ 217 @Override // MailReceiveListener 218 public boolean receive( final MailMessage message ) { 219 final String msg = "[" + counter++ + "]" + message.getMessageID() + " 受信中" ; 220 System.out.println( msg ); 221 222 // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..; 223 if( mailSaveDir == null ) { 224 System.out.println( message.getSubject() ); 225 System.out.println( message.getContent() ); 226 } 227 else { 228 message.saveMessage( mailSaveDir ); 229 } 230 231 if( fileSaveDir != null ) { 232 message.saveAttachFiles( fileSaveDir,useMsgId ); 233 } 234 return true ; 235 } 236 } 237 238 /** 239 * main メソッドです。 240 * 241 * @param args コマンド引数配列 242 */ 243 public static void main ( final String[] args ) { 244 final MailReceiver receiver = new MailReceiver(); 245 try { 246 LOGGER.info( "メール受信処理を開始します ---------------------------------------------" ); 247 receiver.start( args ); 248 LOGGER.info( "正常に終了しました。" ); 249 } 250 catch( final Throwable th ) { 251 final String errMsg = "メール受信中に例外が発生しました。 " 252 + CR + receiver.argment 253 + CR + th.getMessage() ; 254 LOGGER.log( Level.SEVERE,errMsg, th ); 255 } 256 } 257}