JavaMail bug?

M

Martin Gregorie

Note that it does not include AUTH, so no authentication will be allowed
and the client should not attempt it.
Fair point.
This isn't a good idea. It's an open invitation to spammers to verify
the existence of every recipient in your domain.
Except that this server really is private: my firewall blocks all inbound
connection requests and so its only contact with the outside world are
its outbound SMTP connections to my ISP's mail server when it needs to
send mail. Incoming mail is fetched by getmail and passed to the MTA via
the Postfix.sendmail utility.
I presume that this is due to the fact that the connect() above failed.
You have specified authentication by using a user/password, but the
connection does not allow authentication. When you subsequently use
tr.send() there is no open session so a default session is created which
appears to be to localhost.
OK, that makes sense.

Your point about Transport.send() being static would seem to explain the
behaviour I'm seeing, but there's still a heap of anomalies, mainly in
the documentation:

- Transport.send() says that its not a good idea to inherit the
connection from a Session and doesn't provide a suitable way of setting
the hostname (at least its docs don't mention one or mention the use of
properties, though obviously they are used by it.

- now go and look at SMTPTransport. Its documentation includes
example code doing as we did, and getting the connection from Session.

Gaargh!

The double connect is now explained by the Session.connect() making one
connection and Transport.send() making a second
 
N

Nigel Wade

Fair point.

Except that this server really is private: my firewall blocks all inbound
connection requests and so its only contact with the outside world are
its outbound SMTP connections to my ISP's mail server when it needs to
send mail. Incoming mail is fetched by getmail and passed to the MTA via
the Postfix.sendmail utility.

Ok. Fairy snuff.

Personally I'd still get rid of it unless you are actively using it.
It's somewhat in the realm of "security by obscurity". There's a potential for the vulnerability to be exposed, or for the configuration to migrate somewhere where it is exposed. Imagine your firewall goes down, the mail server stops working and users are clamouring for their email (it's like a drug here, users will get along without any other system, but not the mail server). Panic, Panic. Bypass the broken firewall to get the mail server back online - and now you're exposed.
OK, that makes sense.

Your point about Transport.send() being static would seem to explain the
behaviour I'm seeing, but there's still a heap of anomalies, mainly in
the documentation:

- Transport.send() says that its not a good idea to inherit the
connection from a Session and doesn't provide a suitable way of setting
the hostname (at least its docs don't mention one or mention the use of
properties, though obviously they are used by it.

- now go and look at SMTPTransport. Its documentation includes
example code doing as we did, and getting the connection from Session.

I see the documentation showing use of Transport.sendMessage() (an abstract
instance method) following a Session.getTransport().

I don't see use of Transport.send().
 
M

Martin Gregorie

Personally I'd still get rid of it unless you are actively using it.
It's somewhat in the realm of "security by obscurity". There's a
potential for the vulnerability to be exposed, or for the configuration
to migrate somewhere where it is exposed.
Its unlikely that anything like that would happen. This is my house
server that I'm describing. The config is whatever I set it to and nobody
else is ever likely to touch it.
Imagine your firewall goes
down, the mail server stops working
Indeed. If the firewall breaks, nothing will work until it gets replaced.
I see the documentation showing use of Transport.sendMessage() (an
abstract instance method) following a Session.getTransport().
Sure, but they are all static apart from sendMessage, which is abstract.
I don't see use of Transport.send().
True enough.
 
N

Nigel Wade

On Tue, 09 Aug 2011 13:31:49 +0100, Nigel Wade wrote:

Sure, but they are all static apart from sendMessage, which is abstract.

It's sendMessage() which they use in the example, not any of the static
methods - that's the important fact. sendMessage() must be implemented
by whatever class creates the Transport which is returned by
Session.getTransport(), it could not instantiate a Transport unless it
had implemented the abstract methods.
 
M

Martin Gregorie

It's sendMessage() which they use in the example, not any of the static
methods - that's the important fact. sendMessage() must be implemented
by whatever class creates the Transport which is returned by
Session.getTransport(), it could not instantiate a Transport unless it
had implemented the abstract methods.
Thanks for the reminder. I was knackered last night due to having flown a
4 1/4 hour soaring flight yesterday PM and that didn't register.

I still think we're dealing with an ugly bit of design, though: IMO there
too many ways of specifying the MTA host and login parameters and, worse,
the design decision to use static methods has prevented these from being
orthogonal to the methods that send messages.
 
M

Martin Gregorie

I've just been reviewing the JavaMail API as it's a while since I used
it. You need to be aware that Transport.send() is a /static/ method. I
presume this means it takes no note of any connection established by an
object of class Transport, since the class method has no knowledge of
any contents of any Transport object. That probably explains why it uses
the values in the Session, not those established by the Transport object
you've created.
Final comment:

On Sunday this whole mess niggled me again, so I ripped out the property
setting the default MTAname and replaced the call of tr.send(msg) with
tr.sendMessage(msg, recipients) so the Transport acquired from the
Session is used. This all works as expected: there's only the one EHLO
conversation and the recipient is validated (which I don't remember
seeing earlier).
 
N

Nigel Wade

Final comment:

On Sunday this whole mess niggled me again, so I ripped out the property
setting the default MTAname and replaced the call of tr.send(msg) with
tr.sendMessage(msg, recipients) so the Transport acquired from the
Session is used. This all works as expected: there's only the one EHLO
conversation and the recipient is validated (which I don't remember
seeing earlier).

Yes, I think that's the best way to do authentication. If you look at
the top of the Javadocs for com.sun.mail.smtp (the protocol which is
actually used behind the scenes, it's not exactly obvious because the
design hides this from you) it states:

To use SMTP authentication you'll need to set the mail.smtp.auth
property (see below) or provide the SMTP Transport with a username and
password when connecting to the SMTP server. You can do this using one
of the following approaches:

* Provide an Authenticator object when creating your mail Session
and provide the username and password information during the
Authenticator callback.

Note that the mail.smtp.user property can be set to provide a
default username for the callback, but the password will still need to
be supplied explicitly.

This approach allows you to use the static Transport send method
to send messages.

* Call the Transport connect method explicitly with username and
password arguments.

This approach requires you to explicitly manage a Transport
object and use the Transport sendMessage method to send the message. The
transport.java demo program demonstrates how to manage a Transport
object. The following is roughly equivalent to the static Transport send
method, but supplies the needed username and password:

Transport tr = session.getTransport("smtp");
tr.connect(smtphost, username, password);
msg.saveChanges(); // don't forget this
tr.sendMessage(msg, msg.getAllRecipients());
tr.close();
 
M

Martin Gregorie

Yes, I think that's the best way to do authentication. If you look at
the top of the Javadocs for com.sun.mail.smtp (the protocol which is
actually used behind the scenes, it's not exactly obvious because the
design hides this from you) it states:

To use SMTP authentication you'll need to set the mail.smtp.auth
property (see below) or provide the SMTP Transport with a username and
password when connecting to the SMTP server. You can do this using one
of the following approaches:
Yes, I found that too.
Transport tr = session.getTransport("smtp");
tr.connect(smtphost, username, password); msg.saveChanges();
// don't forget this tr.sendMessage(msg,
msg.getAllRecipients());
tr.close();
I'm not calling Message.saveChanges(), but as something wrapped your text
up in a bit of a ball I'm not sure that your 'don't forget' refers to.
Instead I hung onto the recipient array and just passed it into
Transport.sendMessage(). It also works correctly.
 
N

Nigel Wade

I'm not calling Message.saveChanges(), but as something wrapped your text
up in a bit of a ball I'm not sure that your 'don't forget' refers to.
Instead I hung onto the recipient array and just passed it into
Transport.sendMessage(). It also works correctly.

It isn't "mine". It's a quote from the Javadocs. It refers to the
saveMessage(), which I've never used. I presume that's in case you want
to save the changes to the messages into some message store (Drafts?).
The entire package is rather convoluted for simple message
generation/submission.

I don't know why you don't see the text correctly. The post appears ok
viewed in my newsreader (Thunderbird). It's flowed text, maybe your
newsreader doesn't like that. But, as far as I can tell, the code part
is correctly line-wrapped anyway, rather than flowed.
 
M

Martin Gregorie

It isn't "mine". It's a quote from the Javadocs. It refers to the
saveMessage(), which I've never used.
Thanks for the clarification.
I presume that's in case you want
to save the changes to the messages into some message store (Drafts?).
Thats what the method description says its for.
The entire package is rather convoluted for simple message
generation/submission.
It certainly gives me the impression of having been written before it was
designed or documented and that it wasn't fully understood by the
documentation's author.
I don't know why you don't see the text correctly. The post appears ok
viewed in my newsreader (Thunderbird).
OK. I thought that finding "msg.saveMessage();" had been wrapped onto the
end of the preceding line since the rest of the snippet is one statement
per line. I've noticed that some constructions - particularly 'bulleted
points', i.e. lines each starting with '- ' tend to get wrapped by
something in USENET and thought this was another case of it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top