Häufig steht man bei Webprojekten vor der Anforderung E-Mails zu versenden, zum Beispiel für Bestellbestätigungen, das Versenden von Login Informationen oder Newslettern.
In einem kleinen Beispiel werde ich zeigen, wie man sich eine Klasse schreibt, von der man in seiner ganzen Webanwendung aus E-Mail versenden kann. Damit das Versenden der E-Mail sich nicht bei der Antwortzeit des Benutzers bemerkbar macht, z.B. durch den Aufbau der Verbindung zum E-Mail Server, werden wir das Versenden der E-Mail asynchron ausführen.
Als erstes ladet ihr euch das JavaMail Paket und das Activation Paket von Sun herunter, die darin enthaltenen Dateien mail.jar und activation.jar packt ihr in euer WEB-INF/lib Verzeichnis.
Wir benötigen für dieses Beispiel drei Klassen. Als erstes eine Klasse Mail die unsere eigentliche E-Mail repräsentiert.
import java.util.List;
public class Mail
{
private String sender, to, bcc, cc, subject, text;
private List< MailAnhang > anhaenge;
public Mail(String sender, String to, String subject, String text)
{
super();
this.sender = sender;
this.to = to;
this.subject = subject;
this.text = text;
}
public List< MailAnhang >; getAnhaenge()
{
return anhaenge;
}
public String getBcc()
{
return bcc;
}
public String getCc()
{
return cc;
}
public String getSender()
{
return sender;
}
public String getSubject()
{
return subject;
}
public String getText()
{
return text;
}
public String getTo()
{
return to;
}
public void setAnhaenge(List< MailAnhang > anhaenge)
{
this.anhaenge = anhaenge;
}
public void setBcc(String bcc)
{
this.bcc = bcc;
}
public void setCc(String cc)
{
this.cc = cc;
}
public void setSender(String sender)
{
this.sender = sender;
}
public void setSubject(String subject)
{
this.subject = subject;
}
public void setText(String text)
{
this.text = text;
}
public void setTo(String to)
{
this.to = to;
}
}
Und die Klasse MailAnhang, falls man zum Beispiel eine Rechnung versenden will.
import java.io.File;
public class MailAnhang
{
private String name;
private String mime;
private File file;
public MailAnhang(String name, String mime, File file)
{
super();
this.name = name;
this.mime = mime;
this.file = file;
}
public String getName()
{
return name;
}
public String getMime()
{
return mime;
}
public File getFile()
{
return file;
}
}
Jetzt kommen wir zu der Klasse MailSender, die unsere E-Mail versenden wird. Damit es diesen Dienst in unsere Anwendung nur einmal gibt, ist das Ganze als Singleton implementiert. Die Mails werden durch die Methode sendMail(Mail m) unserer Liste übergeben. Und dieses List wird zyklisch von einem separaten Thread überprüft, ob es neue Einträge gibt.
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class MailSender
{
private static final Log log = LogFactory.getLog(MailSender.class);
private InternetAddress addressFrom;
private InternetAddress addressTo;
private InternetAddress addressCc;
private InternetAddress addressBcc;
private MimeMessage msg;
private MimeMultipart content;
private Session session;
private Transport transport;
private Properties props = new Properties();
private String smtpHost = "deinesmtphost.de";
private String smtpBenutzer = "benutzer";
private String smtpPasswort = "passwort";
private int counter = 0;
/** Die MailQueue hier werden die Mail abgelegt bevor Sie asynchron versendet werden */
private LinkedList mailQueue;
/** Privates Klassenattribut, einzige Instanz der Klasse wird erzeugt. */
private static final MailSender INSTANCE = new MailSender();
/**
* Statische Methode "getInstance()" liefert die einzige Instanz der Klasse
* zurück. Dadurch gibt es nur eine zentrale Instance in der Webanwendung die E-Mails versendet.
*/
public static MailSender getInstance()
{
return INSTANCE;
}
/** Konstruktor ist privat, darf nicht von außen instanziert werden. */
private MailSender()
{
mailQueue = new LinkedList();
props.put("mail.smtp.host", smtpHost);
this.counter = 0;
session = Session.getDefaultInstance(props, null);
try
{
transport = session.getTransport("smtp");
}
catch (Exception e)
{
log.error("Fehler beim initialisieren der Klasse : " + e, e);
}
Thread m = new Thread(new Mailer());
m.start();
}
/** Übergeben der E-Mail an die MailQueue*/
public boolean sendMail(Mail m)
{
try
{
mailQueue.add(m);
return true;
}
catch (Exception e)
{
return false;
}
}
/** Der Mailer versendet Die E-Mails im asynchron im Hintergrund als eigener Thread */
private class Mailer extends Thread
{
int threadnummer;
Mailer()
{
super();
}
@Override
public void run()
{
// Endlosschleife zum zyklischen überprüfen ob neue Mails zum versenden vorhanden sind
while (true)
{
try
{
//Sind neue Mails vorhanden?
if (!mailQueue.isEmpty())
{
//Die erste Mail aus der Queue holen
Mail m = mailQueue.removeFirst();
try
{
content = new MimeMultipart("alternativ");
msg = new MimeMessage(session);
//Die Adresse des Versenders
addressFrom = new InternetAddress(m.getSender());
msg.setFrom(addressFrom);
//Die Adresse des Empfängers
addressTo = new InternetAddress(m.getTo());
msg.addRecipient(Message.RecipientType.TO, addressTo);
//Die Adresse des Kopieemfängers
if (m.getCc() != null && m.getCc().length() > 3)
{
addressCc = new InternetAddress(m.getCc());
msg.addRecipient(Message.RecipientType.CC, addressCc);
}
//Die Adresse des Blindkopieempfängers
if (m.getBcc() != null && m.getBcc().length() > 3)
{
addressBcc = new InternetAddress(m.getBcc());
msg.addRecipient(Message.RecipientType.BCC, addressBcc);
}
//Der Betreff
msg.setSubject(m.getSubject());
//Der eigentliche Text im HTML Format
MimeBodyPart text = new MimeBodyPart();
text.setContent(m.getText(), "text/html");
content.addBodyPart(text);
//Die Anhänge
List< MailAnhang > dateien = m.getAnhaenge();
if(dateien != null)
{
for (MailAnhang mailAnhang : dateien)
{
BodyPart anhang = new MimeBodyPart();
anhang.setFileName(mailAnhang.getName());
InputStream is = new FileDataSource(mailAnhang.getFile()).getInputStream();
DataSource dh = new ByteArrayDataSource(is, mailAnhang.getMime());
anhang.setDataHandler(new DataHandler(dh));
content.addBodyPart(anhang);
}
}
//Setzen des Content
msg.setContent(content);
msg.saveChanges();
transport = session.getTransport("smtp");
//Verbindung zu Mailserver aufbauen
transport.connect(smtpHost, smtpBenutzer, smtpPasswort);
transport.sendMessage(msg, msg.getAllRecipients());
transport.close();
counter++;
if (log.isDebugEnabled()) log.debug("Mail " + counter + " " + m.getSubject() + " erfolgreich gesendet");
}
catch (MessagingException me)
{
log.error("Fehler beim Versenden der Mail : " + me, me);
}
catch (Exception e)
{
log.error("Fehler beim Versenden der Mail : " + e, e);
}
}
else
{
//Alle wieviel Minuten soll die Queue auf neue Mails überprüft und diese versendet werden.
Thread.sleep(600l);
}
}
catch (Exception e)
{
log.error("Fehler beim Versenden der Mail : " + e, e);
}
}
}
}
}
Um jetzt eine Mail zu versenden, brauchen wir in unserer Webanwendung nur noch folgenden Code aufrufen.
Mail m = new Mail("empfaenger@domain.de", "versender@domain.de" , "Mein Betreff", "Und hier der Text der versendet wird.");
List anhang = new LinkedList ();
anhang.add(new MailAnhang("PDF Rechnung", "application/pdf", pdfFile));
m.setAnhaenge(anhang);
MailServer.getInstance().sendMail(m);
Eine Alternative bietet http://commons.apache.org/email/ — das sieht dann so ähnlich aus. Christian
Moin, in der Klasse “Mail” – “public void setAnhaenge(List; anhaenge)” Ich denke mal ein Semikolon zu viel .-) Klasse “MailSender” unter “Die Anhänge” – “for (MailAnhang mailAnhang : dateien)” Netbeans zeigt mir dort ein Typenkonflikt an (ObjektListe). Ein Fehler? Wie lautet es richtig? Mit Gruß
PS: Hoffentlich nun mit richtiger Anzeigeformatierung .-)
Danke für die Fehlermeldung, ich habe den Code gleich mal korrigiert.
Entweder du nutzt Generics die seit Java 5 verfügbar sind. Oder Du musst die Objecte in der Liste noch auf MailAnhang casten.