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