/*
Copyright (c) 2002 Red Shed Software. All rights reserved.
by Jonathan 'Wolf' Rentzsch (jon at redshed dot net)
*/
package er.javamail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Enumeration;
import javax.activation.DataHandler;
import javax.mail.Message;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webobjects.appserver.WOApplication;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOSession;
import com.webobjects.foundation.NSArray;
/**
* <div class="en">
* Drop-in replacement for WOMailDelivery.
* <p>
* ERWOMailDelivery operates just the same as WOMailDelivery, and has all of the same limitations and weird API.
* However, instead of using the Sun's broken* and unsupported sun.net.smtp.SmtpClient, it uses JavaMail.
* <p>
* <i>*sun.net.smtp.SmtpClient doesn't put addresses in angle brackets when sending the SMTP MAIL FROM command. Many
* SMTP servers won't work with it.</i>
* </div>
*
* <div class="ja">
* WOMailDelivery の替わりに使用します。
* <p>
* ERWOMailDelivery は WOMailDelivery と同じように動作します。全く同じ制限と不思議な API を持っています。
* 正しい、Sun 社の壊れているサポートしない sun.net.smtp.SmtpClient と違って JavaMail を使用しています。
* <p>
* <i>*sun.net.smtp.SmtpClient は SMTP MAIL FROM で送信するアドレスを括弧で囲まないので、大抵の SMTP サーバは動作しないのです。</i>
* </div>
*
* @author Jonathan 'Wolf' Rentzsch (jon at redshed dot net)
* @see <A
* HREF="file://localhost/Ten/Developer/Documentation/WebObjects/Reference/com/webobjects/appserver/WOMailDelivery.html">com.webobjects.appserver.WOMailDelivery</A>
*/
public class ERWOMailDelivery {
/**
* <div class="en">
* @return The shared instance.
* </div>
*
* <div class="ja">
* @return 共有インスタンス
* </div>
*/
public static ERWOMailDelivery sharedInstance() {
if (_sharedInstance == null)
_sharedInstance = new ERWOMailDelivery();
return _sharedInstance;
}
/**
* <div class="en">Default constructor (don't use). Use {@link #sharedInstance()} instead. </div>
* <div class="ja">未使用のコンストラクタ: {@link #sharedInstance()} を使用します。 </div>
*/
protected ERWOMailDelivery() {
// Just here & protected so folks don't try to construct directly.
}
/**
* <div class="en">
* Creates and optionally sends a plain text email.
*
* @param fromEmailAddress
* Originating email address. Required.
* @param toEmailAddresses
* Destination email address. Required.
* @param bccEmailAddresses
* Array of Strings containing additional addressed to BCC. Can be null.
* @param subject
* Subject the message. Can be null.
* @param message
* Body the the message. Required.
* @param sendNow
* Whether to send the message right away. If you're going to send the message right away, it's faster to
* set sendNow to true than set it to false and calling {@link #sendEmail(String)} later.
* </div>
*
* <div class="ja">
* 標準テキスト・メールを作成と送信します。
*
* @param fromEmailAddress - 送信元メール・アドレス(必須)
* @param toEmailAddresses - 送信先メール・アドレス NSArray(必須)
* @param bccEmailAddresses - BCC メール・アドレス NSArray (Null可)
* @param subject - メール・サブジェクト(Null可)
* @param message - メッセージ(必須)
* @param sendNow - true ですぐに送信します。
* すぐに送信時には false を設定し後で {@link #sendEmail(String)} で送信するよりも true の方が早い
* </div>
*/
public String composePlainTextEmail(String fromEmailAddress, NSArray<String> toEmailAddresses, NSArray<String> bccEmailAddresses, String subject, String message, boolean sendNow) {
// /JAssert.notEmpty( fromEmailAddress );
// /JAssert.notNull( toEmailAddresses );
// /JAssert.greaterThan( toEmailAddresses.count(), 0 );
// /JAssert.notEmpty( message );
// /JAssert.notNull( ERJavaMail.sharedInstance().defaultSession() );
MimeMessage smtpMessage = newMimeMessage(fromEmailAddress, toEmailAddresses, bccEmailAddresses, subject, message, "text/plain", sendNow);
return mimeMessageToString(smtpMessage);
}
/**
* <div class="en">
* Creates and optionally sends a WOComponent as email.
*
* @param fromEmailAddress
* Originating email address. Required.
* @param toEmailAddresses
* Destination email address. Required.
* @param bccEmailAddresses
* Array of Strings containing additional addressed to BCC. Null OK.
* @param subject
* Subject the the message. Null OK.
* @param component
* Body the the message. Required.
* @param sendNow
* Whether to send the message right away. If you're going to send the message right away, it's faster to
* set sendNow to true than set it to false and calling {@link #sendEmail(String)} later.
* </div>
*
* <div class="ja">
* WOComponent メールを作成と送信します。
*
* @param fromEmailAddress - 送信元メール・アドレス(必須)
* @param toEmailAddresses - 送信先メール・アドレス NSArray(必須)
* @param bccEmailAddresses - BCC メール・アドレス NSArray (Null可)
* @param subject - メール・サブジェクト(Null可)
* @param component - コンポーネント(必須)
* @param sendNow - true ですぐに送信します。
* すぐに送信時には false を設定し後で {@link #sendEmail(String)} で送信するよりも true の方が早い
* </div>
*/
public String composeComponentEmail(String fromEmailAddress, NSArray<String> toEmailAddresses, NSArray<String> bccEmailAddresses, String subject, WOComponent component, boolean sendNow) {
// XXX the component parameter above was 'message'. the real parameter could be renamed.
// /JAssert.notEmpty( fromEmailAddress );
// /JAssert.notNull( toEmailAddresses );
// /JAssert.greaterThan( toEmailAddresses.count(), 0 );
// /JAssert.notNull( component );
// /JAssert.notNull( component.context() );
// /JAssert.notNull( ERJavaMail.sharedInstance().defaultSession() );
WOSession session = component.context()._session();
String response;
component.context().generateCompleteURLs();
if (session == null) {
response = component.generateResponse().contentString();
}
else {
boolean oldStoresIDsInURLs = session.storesIDsInURLs();
session.setStoresIDsInURLs(true);
response = component.generateResponse().contentString();
session.setStoresIDsInURLs(oldStoresIDsInURLs);
}
component.context().generateRelativeURLs();
// --
MimeMessage smtpMessage = newMimeMessage(fromEmailAddress, toEmailAddresses, bccEmailAddresses, subject, response, "text/html", sendNow);
return mimeMessageToString(smtpMessage);
}
/**
* <div class="en">
* Sends the RFC822 mail string created with either
* {@link #composePlainTextEmail(String,NSArray,NSArray,String,String,boolean)} or
* {@link #composeComponentEmail(String,NSArray,NSArray,String,WOComponent,boolean)}. It's faster to call either
* method with the sendNow parameter set to true than to use this method.
* </div>
*
* <div class="ja">
* {@link #composePlainTextEmail(String,NSArray,NSArray,String,String,boolean)} や
* {@link #composeComponentEmail(String,NSArray,NSArray,String,WOComponent,boolean)} で
* 作成されている RFC822 メールを送信します。
* </div>
*/
public void sendEmail(String mailString) {
// /JAssert.notEmpty( mailString );
// /JAssert.notNull( ERJavaMail.sharedInstance().defaultSession() );
ByteArrayInputStream bais = new ByteArrayInputStream(mailString.getBytes());
try {
MimeMessage smtpMessage = new MimeMessage(ERJavaMail.sharedInstance().defaultSession(), bais);
(new MimeMessageMailDelivery(smtpMessage)).sendMail();
}
catch (Exception x) {
log.error("Could not send mail.", x);
}
}
@Override
public String toString() {
return "<ERWOMailDelivery smtpHost=" + WOApplication.application().SMTPHost() + ">";
}
// Private Implementation.
private static final Logger log = LoggerFactory.getLogger(ERWOMailDelivery.class);
private static ERWOMailDelivery _sharedInstance = null;
private MimeMessage newMimeMessage(String fromEmailAddress, NSArray<String> toEmailAddresses, NSArray<String> bccEmailAddresses, String subject, String message, String contentType, boolean sendNow) {
// /JAssert.notEmpty( fromEmailAddress );
// /JAssert.notNull( toEmailAddresses );
// /JAssert.greaterThan( toEmailAddresses.count(), 0 );
// /JAssert.notEmpty( message );
// /JAssert.notEmpty( contentType );
// /JAssert.notNull( ERJavaMail.sharedInstance().defaultSession() );
MimeMessage smtpMessage = null;
try {
smtpMessage = new MimeMessage(ERJavaMail.sharedInstance().defaultSession());
smtpMessage.setFrom(new InternetAddress(fromEmailAddress));
Enumeration<String> addressEnumerator = toEmailAddresses.objectEnumerator();
while (addressEnumerator.hasMoreElements()) {
String address = addressEnumerator.nextElement();
smtpMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(address));
}
if (bccEmailAddresses != null && bccEmailAddresses.count() > 0) {
addressEnumerator = bccEmailAddresses.objectEnumerator();
while (addressEnumerator.hasMoreElements()) {
String address = addressEnumerator.nextElement();
smtpMessage.addRecipient(Message.RecipientType.BCC, new InternetAddress(address));
}
}
smtpMessage.setSubject(subject);
smtpMessage.setContent(message, contentType);
if (sendNow)
(new MimeMessageMailDelivery(smtpMessage)).sendMail();
}
catch (Exception x) {
log.error("Could not create Mime message", x);
}
return smtpMessage;
}
private static String mimeMessageToString(MimeMessage smtpMessage) {
// /JAssert.notNull( smtpMessage );
String result = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
smtpMessage.writeTo(baos);
result = baos.toString();
}
catch (Exception x) {
log.error("Could not create String from Mime message.", x);
}
return result;
}
private static class MimeMessageMailDelivery extends ERMailDelivery {
public MimeMessageMailDelivery(MimeMessage msg) {
super();
setMimeMessage(msg);
}
@Override
protected DataHandler prepareMail() {
MimeMessage msg = mimeMessage();
String contentType = "text/plain";
try {
contentType = msg.getContentType();
}
catch (javax.mail.MessagingException x) {
ERWOMailDelivery.log.error("Could not get content type.", x);
}
return new DataHandler(ERWOMailDelivery.mimeMessageToString(msg), contentType);
}
}
}