|
The Java Specialists' Newsletter
Issue 131 2006-08-28
Category:
Tips and Tricks
Java version: JDK 1.5 Sending Emails from Javaby Dr. Heinz M. KabutzAbstract:
In this newsletter, we show how simple it is to send
emails from Java. This should obviously not be used for
sending unsolicited emails, but will nevertheless illustrate
why we are flooded with SPAM.
Welcome to the 131st edition of The Java(tm) Specialists' Newsletter. This will be one of my
last newsletters sent from South Africa, as we are moving to
Greece in October. I sold my trusty Alfa Romeo 156 Twin Spark
last week. At least she (sniff sniff) was sold to a good
friend.
Since the last newsletter, our children count has increased by
50%. We are grateful for a safe arrival. Have
a look at the announcement :)
Here is another copy of the quiz that I sent last month, which
less than 25% got right. Even if you cannot make it to Oslo in
September for my tutorial, have a look if you know the answer:
import java.util.*;
public class Conference {
private Collection delegates = new ArrayList();
public void add(String... names) {
Collections.addAll(delegates, names);
}
public void removeFirst() {
delegates.remove(0);
}
public String toString() {
return "Conference " + delegates;
}
public static void main(String[] args) {
Conference sun_tech_days = new Conference();
sun_tech_days.add("Herman", "Bobby", "Robert");
sun_tech_days.removeFirst();
System.out.println(sun_tech_days);
}
}
Upcoming Java Specialist Master Courses:
- please click here to sign up.
As from May 2010, we are also offering this course on the island of Crete. We
only accept 6 students per class in Crete, due to the size of our conference
room. Please book early to avoid disappointment!
San Jose CA, Mar 16-19 2010, $3500 Ottawa, Canada, Mar 22-25 2010, $3500 Oslo, Norway, Apr 13-16 2010, Kr 24500 Montreal, Canada, Apr 20-23 2010, $3500 Toronto, Canada, May 17-20 2010, $3500 Chania, Crete, May 25-28, Jun 29-Jul 2 or Aug 24-27 2010, €2500
In-house courses if these dates or locations do not suit you - click here for more information. Sending Emails from Java
Sometimes we need to send an email to a group of friends to
announce some event (birth of child, move to Greece, farewell
party). Due to the scourge of SPAM, we have to be careful how
we do this, otherwise our email will be caught in the net and
the other party will not see it. Over the years of publishing
this email newsletter, I have discovered several things:
Do not SPAM.
Don't start an email with "Dear ..."
If possible, avoid HTML tags. Text is best.
Definitely avoid JavaScript.
Don't send an email to 100 people by putting their addresses
in the "TO", "CC" or "BCC" fields.
Use a SMTP server on a static IP address.
Do not SPAM.
Let us imagine that I want to invite 30 friends for a "braai",
which is a South African version of the barbeque. It works a
bit differently here. First oi Shff, when we say: come at 18:00,
we mean 20:00. And if you do come at 20:00, don't expect the
fire to have started yet. Another curious feature is that it is
fairly common to ask your guests to bring their own meat and
drinks. This way, the braai scales better. So here is my
invitation, "braai.txt", where the first line is the subject:
Invitation to Braai 5th August
We are having a braai at our house on the 5th of August at 18:00
to celebrate the birth of our daughter, Evangeline Kineta Kabutz.
Be there or be square. Bring own meat and drinks. We will
provide the salads, the fire and the music.
Heinz + Helene
Of course, we also need a list of email addresses that we can
send the invitation to. These can be in various formats, but
the one that I prefer is "FirstName Surname <email>". Here
is the start of my file "addresses.txt":
Heinz Kabutz <heinz@javaspecialists.eu>
Peter East <peter.east@javaspecialists.eu>
Bad Name <bad.name@funkyunregistereddomain.com>
We need to create a utility class called FileCollection, before
we delve into the emailing. The FileCollection is a
Collection of Strings that pulls in the contents of a text file
at start up and contains all the lines as elements.
package com.cretesoft.mailer;
import java.util.*;
import java.io.*;
public class FileCollection extends ArrayList<String> {
public FileCollection(String filename) throws IOException {
BufferedReader in = new BufferedReader(new FileReader(filename));
String s;
while ((s = in.readLine()) != null) {
add(s);
}
in.close();
}
}
We need another utility class called MessageProvider, which
extracts the subject and the message body from a file:
package com.cretesoft.mailer;
import java.io.*;
import java.util.*;
public class MessageProvider {
private final String subject;
private final String content;
public MessageProvider(String filename) throws IOException {
Iterator<String> lines = new FileCollection(filename).iterator();
subject = lines.next();
StringBuilder cb = new StringBuilder();
while(lines.hasNext()) {
cb.append(lines.next());
cb.append('\n');
}
content = cb.toString();
}
public final String getSubject() {
return subject;
}
public final String getContent() {
return content;
}
}
Now comes the tricky part of deciding which SMTP server to use.
If you travel alot, or move between ISPs and networks, you
should use a server that allows you to authenticate yourself.
Sending emails from your own machine, especially if you have a
dynamic IP address, is almost guaranteed to land you in the
SPAM bin. You will have to make your own arrangements with your
ISP to find out what the SMTP server settings are.
The MailSender class is currently hardcoded with my own settings
which you need to replace with your own. All it does is create
a transport for SMTP and then allow you to send the message to
an email address.
package com.cretesoft.mailer;
import javax.mail.*;
import javax.mail.internet.*;
import java.util.*;
public class MailSender {
private static final String SMTP_SERVER =
"smtp.javaspecialists.eu";
private static final String USERNAME =
"heinz@javaspecialists.eu";
private static final String PASSWORD = "some_password";
private static final String FROM =
"Dr Heinz M. Kabutz <heinz@javaspecialists.eu>";
private static final String mailer = "TJSNMailer";
private final Transport transport;
private final Session session;
private final MessageProvider provider;
public MailSender(MessageProvider provider)
throws MessagingException {
this.provider = provider;
Properties props = System.getProperties();
props.put("mail.smtp.host", SMTP_SERVER);
props.put("mail.smtp.auth", "true");
// Get a Session object
session = Session.getInstance(props, null);
transport = session.getTransport("smtp");
transport.connect(SMTP_SERVER, USERNAME, PASSWORD);
}
public void sendMessageTo(String to) throws MessagingException {
Message msg = new MimeMessage(session);
// set headers
msg.setFrom(InternetAddress.parse(FROM, false)[0]);
msg.setHeader("X-Mailer", mailer);
msg.setSentDate(new Date());
msg.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(to, false));
// set title and body
msg.setSubject(provider.getSubject());
msg.setText(provider.getContent());
// off goes the message...
transport.sendMessage(msg, msg.getAllRecipients());
}
}
Depending on how reliable your SMTP server is, you might need to
build in some retries into the sendMessageTo() method.
Lastly we have the Mailer class:
package com.cretesoft.mailer;
import javax.mail.MessagingException;
import java.io.IOException;
public class Mailer {
private final FileCollection to;
private final MessageProvider provider;
public Mailer(String addressFile, String messageFile)
throws IOException {
to = new FileCollection(addressFile);
provider = new MessageProvider(messageFile);
}
public void sendMessages() throws MessagingException {
MailSender sender = new MailSender(provider);
for (String email : to) {
sender.sendMessageTo(email);
System.out.println("Mail sent to " + email);
}
}
public static void main(String[] args) throws Exception {
if (args.length != 2) {
System.err.println(
"Usage: java Mailer address_file message_file");
System.exit(1);
}
long time = -System.currentTimeMillis();
Mailer sender = new Mailer(args[0], args[1]);
sender.sendMessages();
time += System.currentTimeMillis();
System.out.println(time + "ms");
System.out.println("Finished");
}
}
When we run this (with the correct password), we get:
Mail sent to Heinz Kabutz <heinz@javaspecialists.eu>
Mail sent to John Smith <john.smith@javaspecialists.eu>
Mail sent to Bad Name <bad.name@funkyunregistereddomain.com>
17749ms
Finished
Application of Mailer
I use this mailer in several applications. For example, when
you fill in our enquiry
form it sends me a lovely email listing what you
have filled in. In that case, I am sending an HTML email to
myself. Using HTML looks smarter, but might get caught up in
a SPAM net.
Another application for sending emails is when an exception
occurs on some critical applications. This way, we immediately
know when a problem has occurred.
Enhancements
Besides retrying to establish transport connections, you can
also improve the program by using multi-threading to create
several concurrent connections to your ISP's SMTP server. Your
ISP might not allow that. Infact, they might black-list you if
you send too many emails sequentially. However, if it does
allow you, you will get a great performance improvement.
Kind regards
Heinz
Tips and Tricks Articles
Related Java Course
|