|
From: Kopylenko, D. <dko...@ac...> - 2003-10-06 11:52:58
|
Juergen,
The proposed API looks good to me.
Regards,
Dmitriy.
-----Original Message-----
From: j=FCrgen h=F6ller [werk3AT] [mailto:jue...@we...]=20
Sent: Monday, October 06, 2003 2:48 AM
To: Rod Johnson; Kopylenko, Dmitry
Cc: spr...@li...
Subject: Re: [Springframework-developer] Mail support
Rod, Dmitriy,
=20
I agree in terms of Store support - let's concentrate on mail sending =
for
now. I also tend to agree in terms of abstracting JavaMail for simple =
enough
mail sending requirements. I forgot that Session is final, BTW. =
JavaMail is
really messy - API design seems to be an art... ;-)
=20
So let me suggest a meet-in-the-middle solution: As I've initially =
intended,
let's separate transport-related (host, username, password) and
message-related properties, i.e. drop MailSettings in its current form, =
move
transport settings to the MailSender implementation, and introduce a
SimpleMessage class.
=20
As the effect of the current MailTemplate/MailCallback combo =
(overriding
certain pre-defined mail settings) can be achieved with using a
SimpleMessage copy constructor, I suggest to drop MailTemplate and
MailCallback. This leaves SimpleMessage, MailSender, and a =
JavaMailSender
implementation.
=20
To offer more power for those who need it, I suggest to offer =
additional
methods in JavaMailSender. Whoever wants to use those should cast to
JavaMailSender, respectively offer a bean property of type =
JavaMailSender to
be populated by a bean reference. All other application classes can =
work
with the MailSender interface.
=20
MailSender interface users are easily testable with a mock MailSender
implementation. It will be a bit harder with JavaMailSender users, but =
still
possible: A mock JavaMailSender subclass that overrides =
send(MimeMessage)
and send(MimeMessage[]) should allow for easy testing too. Note that a
connection to the mail server is only required for actual mail sending, =
not
for Session setup.
=20
public class SimpleMessage{
private String from;
private String to;
private String[] cc;
private String subject;
private String text;
=20
public SimpleMessage(SimpleMessage original) {
// copy constructor
}
=20
(getters and setters)
}
=20
public interface MailSender {
void send(SimpleMessage message);
}
=20
public class JavaMailSender implements MailSender, InitializingBean {
private String host;
private String username;
private String password;
=20
(getters and setters)
=20
public void afterPropertiesSet() {
// create and keep Session instance
}
=20
public void send(SimpleMessage message) {
// send SimpleMessage via JavaMail
// creating a MimeMessage internally and delegating to =
send(MimeMessage)
}
=20
public void send(MimeMessage message) {
// send JavaMail MimeMessage
// using a Transport instance: connect, sendMessage, disconnect
}
=20
public void send(MimeMessage[] messages) {
// send multiple JavaMail MimeMessages in one batch
// using a Transport instance: connect, multiple sendMessage, =
disconnect
}
=20
public MimeMessage createMimeMessage() {
// create JavaMail MimeMessage for the Session of this sender
// necessary because of MimeMessage(Session) constructor
}
}
=20
I consider this the best of both worlds. Applications can choose to use =
the
full abstraction (MailSender) for simple purposes, or use =
JavaMailSender for
more sophisticated requirements. As testing such apps does not require
mocking JavaMail itself in any case, we should have reached all our =
goals.
=20
What do you think? If we agree on the API design, I'll be happy to =
rework
our mail support that way for 1.0 M2.
=20
Regards,
Juergen
=20
=20
-----Urspr=FCngliche Nachricht-----=20
Von: Rod Johnson [mailto:rod...@in...]=20
Gesendet: So 05.10.2003 11:38=20
An: j=FCrgen h=F6ller [werk3AT]; Kopylenko, Dmitry=20
Cc:=20
Betreff: Re: [Springframework-developer] Mail support
=09
=09
> After in-depth consideration of the mail sending requirements in
werk3AT
products and study of the JavaMail spec, I'm inclined to suggest a
significantly different kind of mail support than the current one.
The main
reasons are certain limitations of the current Spring mail sender,
not
allowing for quite a lot of JavaMail functionality:
>
> 1. How to send blind copies (bcc)?
> 2. How to specify a name for sender or recipient addresses (to
make mail
clients show something like "Juergen Hoeller <jh...@we...>")?
> 3. How to set a charset for subject and text (very important for
localized
mails)?
> 4. How to authenticate against the SMTP server if necessary
(username,
password)?
> 5. How to send multiple messages in batch, within a single mail
server
connection?
> 6. How to access a mail store, i.e. an inbox for reading mails?
>
> The first three require the option to configure a MimeMessage
directly,
instead of just creating one internally from simplified arguments.
There's a
lot of useful functionality in there, we should not try to abstract
that -
just offer simple convenience methods as shortcuts.
>
> Nr. 4 can be overcome by two mechanisms, either passing an
Authenticator
implementation on Session.getInstance, or using a Transport instance
explicitly, passing host, username, and password on the connect
call.
Furthermore, an explicit Transport instance allows to send multiple
messages
within one connection - Nr. 5.
>
> Nr. 6 needs the option to work within a Store, as opposed to a
Transport
for sending.
=09
I'm not sure we need to worry about 6 now, so long as we can support
it
eventually. I think most people are interested primarily in sending
mail.
=09
> So the most appropriate mail support seems to me a MailTemplate
class
that's focused on making JavaMail usage easier rather than general
abstraction. I envisage the following bean properties:
>
> - transportProtocol (default "smtp");
> - storeProtocol (default "pop3");
> - transportHost (aka "mail.smtp.host");
> - storeHost (aka "mail.pop3.host");
> - username (default empty);
> - password (default empty).
>
> The following methods allow to work within a properly managed
Transport or
Store resource, analogous to HibernateTemplate with a Hibernate
Session:
>
> - executeInTransport(MailTransportCallback);
> - executeInStore(MailStoreCallback);
>
> with the following callback interfaces:
>
> public interface MailTransportCallback() {
> doInTransport(Session session, Transport transport);
> }
>
> public interface MailStoreCallback() {
> doInStore(Session session, Store store);
> }
>
> Of course, like with HibernateTemplate, there's a lot of
opportunity for
convenience methods on MailTemplate, to avoid having to implement a
callback: just for transport though, as store-related work will
always be
custom.
>
> - sendMessage(MimeMessage);
> - sendMessages(MimeMessage[]);
> - sendMessage(SimpleMessage message);
> - sendMessage(String from, String to, String subject, String
text);
> - sendMessage(String from, String to, String[] cc, String subject,
String
text);
> - etc.
>
> So sending a plain message is straightforward: Populate a
MailTemplate
with transportHost, username, and password (e.g. in the application
context), pass it to your application object; invoke one of the
sendMessage
methods. But if you need it, the full power of JavaMail is at your
fingertips in a custom callback implementation!
>
> Preconfiguring mail settings is still possible: the
"transportHost" in the
MailTemplate instance, the mail addresses and contents via
SimpleMessage.
The latter with "from", "to", "subject", "text", and a copy
constructor can
serve the role of the current MailSettings, just without "host": a
simplified object representation of a plain message.
>
> SimpleMessage msg =3D new SimpleMessage(preconfiguredMessage);
> msg.setXXX(...);
> mailTemplate.sendMessage(msg);
>
> -----
=09
I agree regarding utility methods. I like the proposed API model
(callbacks
only for custom stuff).
=09
> I know that this is completely different than the current mail
support
model. The main difference is that there is no attempt to abstract
JavaMail
completely, rather a helper for simplified usage like
HibernateTemplate. I
don't see much value in complete abstraction anyway: What
alternative
implementations might there be?
=09
JavaMail is a messy API. There are alternatives such as the old Sun
mail
packages, which I've used successfully, which are usually easier to
configure. I don't think JavaMail is a great abstraction.
=09
> Regarding testing, that should be easier with the above model:
Besides
Session.getInstance, no static JavaMail methods are involved, as
Transport
and Store and handled as instances. Thus, if we isolate the
Session.getInstance call in a protected method, we should be able to
test
our mail support with mock objects, i.e. mock subclasses of Session,
Transport, and Store.
=09
Session is final. Transport is not a real object--ie the most
important
methods are static. JavaMail sucks from a testability perspective,
so I'm
not sure we can avoid those limitations without greater abstraction.
=09
> The main reason why I'm very keen on implementing the above
support is
that the current abstraction is too simple: It loses much of
JavaMail's
power. IMO, the better tradeoff is to work with JavaMail exclusively
and
make its usage simpler.
=09
I think more power is needed. I'm still not convinced that we need
to be
JavaMail only to deliver that.
=09
Regards,
Rod
=09
=09
=09
|