/*
ERMailUtils.java - Camille Troillard - tuscland@mac.com
*/
package er.javamail;
import java.util.Enumeration;
import javax.mail.Address;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOSession;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSMutableArray;
import er.extensions.appserver.ERXApplication;
/**
* <div class="en">
* <code>ERMailUtils</code> contains various utility method related to mail sending.
* </div>
*
* <div class="ja">
* <code>ERMailUtils</code> はメール送信の為のユーティリティー・メソッド集
* </div>
*
* @author <a href="mailto:tuscland@mac.com">Camille Troillard</a>
* @version $Id$
*/
public class ERMailUtils {
private static final Logger log = LoggerFactory.getLogger(ERMailUtils.class);
/**
* <div class="en">
* The shared mail deliverer
* </div>
*
* <div class="ja">
* メール配信の共有インスタンス
* </div>
*/
private static ERMailDeliveryHTML sharedDeliverer;
/**
* <div class="en">
* Accessor to the shared instance of a ERMailDeliveryHTML.
* </div>
*
* <div class="ja">
* 共有インスタンス ERMailDeliveryHTML へのアクセス
* </div>
*
* @return <div class="en">the <code>ERMailDeliveryHTML</code> singleton</div>
* <div class="ja"><code>ERMailDeliveryHTML</code> シングルトン</div>
*/
public static ERMailDeliveryHTML sharedDeliverer() {
if (sharedDeliverer == null) {
sharedDeliverer = ERMailDeliveryHTML.newMailDelivery();
}
return sharedDeliverer;
}
/**
* <div class="en">
* Augmented version of the method found in {@link ERXApplication}. Used to instantiate a WOComponent, typically
* outside of a session.
* </div>
*
* <div class="ja">
* {@link ERXApplication} 内にある同名メソッドの拡張版。
* セッションの外側のインスタンス化に使用します。
* </div>
*
* @param pageName <div class="en">The name of the WOComponent that must be instantiated.</div>
* <div class="ja">インスタンス化する WOComponent 名</div>
* @param sessionDict <div class="en">can be provided in order to set objects/keys in the newly created session of the component. This is useful when one want to preserve state when sending a mail.</div>
* <div class="ja">コンポーネントのために、新規作成されるセッションにセットする「オブジェクト/キー」メール送信にセッション情報が必要な場合に有効です。</div>
*
* @return <div class="en">a newly instantiated <code>WOComponent</code>.</div>
* <div class="ja">新規のインスタンス済み <code>WOComponent</code></div>
*/
public static WOComponent instantiatePage(String pageName, NSDictionary sessionDict) {
WOComponent component = ERXApplication.instantiatePage(pageName);
if (sessionDict != null) {
setDictionaryValuesInSession(sessionDict, component.session());
}
return component;
}
/**
* <div class="en">
* Use this method to send an HTML mail.
* </div>
*
* <div class="ja">
* HTML メール送信に使用します。
* </div>
*
* @param delivery <div class="en">the <code>ERMailDeliveryHTML</code> used to send the mail.</div>
* <div class="ja">メール配信に使用される <code>ERMailDeliveryHTML</code></div>
* @param pageName <div class="en">The name of the WOComponent that must be instantiated.</div>
* <div class="ja">HTMLメッセージを持つインスタンス化する WOComponent 名</div>
* @param alternatePageName <div class="en">The name of the WOComponent that represents for the text that must be displayed when an alternate plain text version of the mail needs to be provided.</div>
* <div class="ja">テキスト・メッセージを持つインスタンス化する WOComponent 名</div>
* @param emailFrom <div class="en">the email address the mail is sent from</div>
* <div class="ja">送信元のメール・アドレス</div>
* @param emailTo <div class="en">the email address the mail is sent to</div>
* <div class="ja">インスタンス化する WOComponent 名</div>
* @param emailReplyTo <div class="en">the email address where the mail must be replied-to.</div>
* <div class="ja">返信先のメール・アドレス</div>
* @param subject <div class="en">the subject of the mail</div>
* <div class="ja">メールのサブジェクト</div>
*/
public static void sendHTMLMail(ERMailDeliveryHTML delivery, String pageName, String alternatePageName, String emailFrom, String emailTo, String emailReplyTo, String subject) {
WOComponent mailPage = ERMailUtils.instantiatePage(pageName, delivery.sessionDictionary());
delivery.newMail();
delivery.setComponent(mailPage);
if (alternatePageName != null) {
String alternateString = null;
WOComponent alternateMailTemplate = ERMailUtils.instantiatePage(alternatePageName, delivery.sessionDictionary());
alternateString = alternateMailTemplate.generateResponse().contentString();
if (alternateString != null) {
delivery.setHiddenPlainTextContent(alternateString);
alternateMailTemplate.session().terminate();
}
}
try {
delivery.setFromAddress(emailFrom);
delivery.setToAddress(emailTo);
delivery.setReplyToAddress(emailReplyTo);
delivery.setSubject((subject == null) ? "" : subject);
delivery.sendMail();
}
catch (javax.mail.MessagingException e) {
// we must handle this exception correctly because the
// mail cannot be sent
log.warn("Could not send email.", e);
}
finally {
// We need to force the termination of the sessions
// because there is some sort of circular reference
// between the context and the session when it is
// instantiated from a newly created WOContext.
mailPage.session().terminate();
}
}
/**
* <div class="en">
* Use this method to send an HTML mail, but default mail delivery.
* </div>
*
* <div class="ja">
* デフォルト配信インスタンスを使用し、 HTML メール送信を行います。
* </div>
*
* @param pageName <div class="en">The name of the WOComponent that must be instantiated.</div>
* <div class="ja">HTMLメッセージを持つインスタンス化する WOComponent 名</div>
* @param alternatePageName <div class="en">The name of the WOComponent that represents for the text that must be displayed when an alternate plain text version of the mail needs to be provided.</div>
* <div class="ja">テキスト・メッセージを持つインスタンス化する WOComponent 名</div>
* @param emailFrom <div class="en">the email address the mail is sent from</div>
* <div class="ja">送信元のメール・アドレス</div>
* @param emailTo <div class="en">the email address the mail is sent to</div>
* <div class="ja">インスタンス化する WOComponent 名</div>
* @param emailReplyTo <div class="en">the email address where the mail must be replied-to.</div>
* <div class="ja">返信先のメール・アドレス</div>
* @param subject <div class="en">the subject of the mail</div>
* <div class="ja">メールのサブジェクト</div>
*/
public static void sendHTMLMail(String pageName, String alternatePageName, String emailFrom, String emailTo, String emailReplyTo, String subject) {
sendHTMLMail(sharedDeliverer(), pageName, alternatePageName, emailFrom, emailTo, emailReplyTo, subject);
}
/**
* <div class="en">
* This method sets the values found in a dictionary into the session's state dictionary. This method is useful when
* one want to transfer current session's state into a newly created session (for example when sending a mail whose
* page has been instantiated with {@link #instantiatePage(String, NSDictionary)} or
* {@link er.extensions.appserver.ERXApplication#instantiatePage(String)}.)
* </div>
*
* <div class="ja">
* このメソッドはディクショナリー内で見つかる値をセッション状態ディクショナリーにセットします。
* このメソッドはカレント・セッションを新セッションに移行する時に有効です。
* (たとえば、{@link #instantiatePage(String, NSDictionary)} や {@link er.extensions.appserver.ERXApplication#instantiatePage(String)}
* でインスタンス化されているページを送信する場合に有効です。)
* </div>
*
* @param dict <div class="en">a <code>NSDictionary</code> value containing the values we want to set in the session parameter.</div>
* <div class="ja">セッションに設定する情報を持つ <code>NSDictionary</code></div>
* @param session <div class="en">a <code>WOSession</code> value that will receive the values contained in the dict parameter.</div>
* <div class="ja">ディクショナリー内に設定されている値をセットする <code>WOSession</code></div>
*/
public static void setDictionaryValuesInSession(NSDictionary dict, WOSession session) {
if ((dict == null) || (session == null)) {
return;
}
Enumeration en = dict.keyEnumerator();
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
Object object = dict.objectForKey(key);
if (object != null) {
log.debug("Setting in session dict value '{}' for key '{}'", object, key);
session.setObjectForKey(object, key);
}
}
}
/** <div class="ja">エンコーディング処理</div> */
public static String encodeString(String string, String charset) {
String encodedString = null;
try {
encodedString = MimeUtility.encodeText(string, charset, !charset.equals(ERMailDelivery.DefaultCharset) ? "B" : null);
}
catch (Exception e) {
encodedString = string;
}
return encodedString;
}
/**
* <div class="en">
* Method that converts NSArray of String emails to InternetAddress [].
* </div>
*
* <div class="ja">
* String メールの NSArray を InternetAddress [] へ変換します。
* </div>
*
* @param addrs <div class="en">a <code>NSArray</code> value</div>
* <div class="ja"><code>NSArray</code></div>
*
* @return <div class="en">an <code>InternetAddress[]</code> value</div>
* <div class="ja"><code>InternetAddress[]</code></div>
* @exception AddressException <div class="en">if an error occurs</div>
* <div class="ja">エラー発生した場合</div>
*/
public static InternetAddress[] convertNSArrayToInternetAddresses(NSArray addrs) throws AddressException {
if (addrs == null)
return new InternetAddress[0];
InternetAddress[] addrArray = new InternetAddress[addrs.count()];
Enumeration en = addrs.objectEnumerator();
for (int i = 0; en.hasMoreElements(); i++) {
String anAddress = (String) en.nextElement();
addrArray[i] = new InternetAddress(anAddress);
}
return addrArray;
}
/**
* <div class="en">
* Method that converts Address [] loaded with either Address or InternetAddress objects to NSArray of String
* emails.
* <p>
* Note that this method will not only accept Address [] but also InternetAddress [].
* </div>
*
* <div class="ja">
* Address [] 又は InternetAddress [] を String メールの NSArray へ変換します。
* <p>
* 注意: Address [] 又は InternetAddress [] が有効です
* </div>
*
* @param addressesArray <div class="en">an <code>Address[]</code> value</div>
* <div class="ja"><code>Address[]</code></div>
*
* @return <div class="en">a <code>NSArray</code> value</div>
* <div class="ja"><code>NSArray</code></div>
*/
@SuppressWarnings("unchecked")
public static NSArray<String> convertInternetAddressesToNSArray(Address[] addressesArray) {
if (addressesArray == null)
return NSArray.EmptyArray;
NSMutableArray<String> addresses = new NSMutableArray<>(addressesArray.length);
for (int i = 0; i < addressesArray.length; i++) {
Address anAddress = addressesArray[i];
String emailAddress = null;
if (anAddress instanceof InternetAddress)
emailAddress = ((InternetAddress) anAddress).toUnicodeString();
else
// anAddress will be a instance of Address
emailAddress = anAddress.toString();
addresses.addObject(emailAddress);
}
return addresses;
}
/**
* <div class="en">
* Method that converts NSDictionary consisting of String emails as keys and String personal names
* to InternetAddress [].
* </div>
*
* <div class="ja">
* String メールの NSDictionary を InternetAddress [] へ変換します。
* キーが String メール・アドレスでオブジェクトが String の個人名
* </div>
*
* @param addrs <div class="en">a <code>NSDictionary</code> with email, personal name as key value pair</div>
* <div class="ja"><code>NSDictionary</code> メール 個人名の KV</div>
* @param charset <div class="en">a <code>String</code> of the charset to use for personal string</div>
* <div class="ja">個人名文字列に使用する文字セット</div>
*
* @return <div class="en">an <code>InternetAddress[]</code> value</div>
* <div class="ja"><code>InternetAddress[]</code></div>
* @exception AddressException <div class="en">if an error occurs</div>
* <div class="ja">エラー発生した場合</div>
*/
public static InternetAddress[] convertNSDictionaryToInternetAddresses(NSDictionary<String, String> addrs, String charset) throws AddressException {
if (addrs == null || addrs.isEmpty())
return new InternetAddress[0];
InternetAddress[] addrArray = new InternetAddress[addrs.count()];
InternetAddress address;
int i = 0;
for (String email : addrs.allKeys()) {
String personal = addrs.objectForKey(email);
if (personal != null && personal.length() > 0) {
address = new InternetAddress();
address.setAddress(email);
try {
address.setPersonal(personal, charset);
}
catch (java.io.UnsupportedEncodingException ex) {
// set the string anyway.
try {
address.setPersonal(personal);
}
catch (Exception e) {
// give up ...
}
}
}
else {
address = new InternetAddress(email);
}
addrArray[i++] = address;
}
return addrArray;
}
/**
* This method will parse a large string of email address that could be separated by commas,
* semicolon, tabs, spaces, carriage returns, (even mixed) and will return an NSArray of addresses(strings)
* @param str
* @return NSArray<String> of email address
*/
public static NSArray<String> emailsFromBulkList(String str) {
if ( (str!=null) && (str.length() > 3) ) {
//str = str.toLowerCase();
str = str.replace("\"", "");
str = str.replace(";", "");
str = str.replace(":", "");
str = str.replace("'", "");
str = str.replace("\n", ",");
str = str.replace("\r", ",");
str = str.replace(" ", ",");
str = str.replace("\t", ",");
str = str.replaceAll(",+", ",");
String[] tokens = str.split(",");
return new NSArray<>(tokens);
}
return null;
}
}