Falconbyte unterstüzen
Betrieb und Pflege von Falconbyte brauchen viel Zeit und Geld. Um dir auch weiterhin hochwertigen Content anbieten zu können, kannst du uns sehr gerne mit einem kleinen "Trinkgeld" unterstützen.
- Achtung: Seit Java JDK 11 muss zusätzlich das java.activation in die Projekt-Bibliothek eingebunden werden.
Vorbereitungen
E-Mail-Adresse bereitstellen
Um das Versenden von E-Mails mit Java Mail zu demonstrieren, haben wir eine E-Mail-Adresse bei GMail angelegt (marcus.algo@gmail.com). Am Besten du registriert dir eine eigene GMail-Adresse, um den E-Mail-Versand damit selbst zu testen.
Damit unser Java-Programm auf die Gmail-Adresse zugreifen kann, muss in den GMail-Sicherheitseinstellungen (https://myaccount.google.com/security) die Option Zugriff durch weniger sichere Apps erst noch eingeschaltet werden:
Andere E-Mail-Anbieter verfahren übrigens ähnlich. Sieh dir am Besten die Sicherheitseinstellungen auch dort einmal an.
Java Mail API einbinden
Die JavaMail API ist das Framework, mit dem wir Mail-Anwendungen bauen können. In Java EE ist JavaMail bereits inklusive. Für die Java Standard Edition (Java SE) musst du sie erst noch als optionales Paket in das Java-Projekt einbinden.
Lade dir hierzu die Bibliotheks-Datei javax.mail.jar runter.
Als nächsten binden wir die JavaMail API in unser Java-Projekt ein:
- IntelliJ: Klicke in der Seitenleiste links ein Java-Projekt an. Gehe anschließend im Programm-Menu auf file > project structure... > libraries. Klicke im Project Structure-Menu auf das + Zeichen und füge jetzt die externe Klassenbibliothek dem Projekt hinzu, indem du die gedownloadete jar-Datei javax.mail.jar auswählst.
- Eclipse: Wähle in der Seitenleiste links ein Java-Projekt aus. Gehe im Programm-Menu oben auf File > Properties. Es erscheint das Menu für die Properties. Wähle darin Java Build Path > Libraries > Add External JARs... und füge die gedownloadete jar-Datei javax.mail.jar hinzu.
Fertig - wir sind nun startbereit ☺️
Wie JavaMail funktioniert
Die JavaMail API besteht aus einem Zusammenspiel verschiedener Klassen. Einige dieser Klassen sehen wir hier:
- Session repräsentiert die Verbindung zum Mailserver und hält die Server-Daten sowie ein Authentificator-Objekt.
- Message ist eine abstrakte Klasse, welche für die Modellierung der E-Mail zuständig ist.
- Multipart ist eine abstrakte Klasse, die als eine Art "Wrapper" für Inhalte der E-Mail dient. Die einzelnen Inhalte der E-Mail sind vom Typ BodyPart.
- Transport modelliert den Transport-Mechanismus für das Senden einer E-Mail.
Die Infografik zeigt uns, dass eine Message eine Instanz von Session und Multipart aufnimmt. Transport benötigt dann wiederum die Message.
Da es sich bei Message, Multipart und BodyPart und abstrakte Klassen handelt, können wir nur mit Objekten von konkreten Unterklassen arbeiten:
Message message = new MimeMessage(session);
Multipart multipart = new MimeMultipart();
BodyPart messageBodyPart = new MimeBodyPart();
E-Mail mit Java senden
Starten wir nun also den Bau unseres Programms zum Versand von E-Mails! Dieser Vorang ist etwas komplexer und du solltest dir Zeit nehmen, ihn zu verstehen. Falls du diese Zeit nicht hast, kann man auch nichts machen. Spring dann einfach zum fertigen Code.
Properties und Adressen setzen
Erstellen wir zunächst eine neue Klasse namens JavaMail. Innerhalb der Main-Methode setzen wir die Daten für den Mail-Server. Für einen GMail-Account sind es folgende Daten:
Properties properties = new Properties();
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.smtp.host", "smtp.gmail.com");
properties.put("mail.smtp.port", "587");
Die einzelnen Elemente werden als Schlüssel-Wert-Paare in einem Properties-Objekt gespeichert.
Gleich darauf speichern wir die Sender-Adresse unseres GMail-Kontos mitsamt Passwort. Außerdem legen wir auch gleich eine Empfänger-Adresse fest:
String myAccount = "marcus.algo@gmail.com"; // GMail-Sender
String myPassword = "*********";
String empfaenger = "empfaenger@irgendwo.de";
Session erstellen
Als nächstes erzeugen wir das Session-Objekt:
Session session = Session.getInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(myAccount, myPassword);
}
});
Die statische Methode Session.getInstance() liefert ein Objekt vom Typ Session zurück. Der Methode werden dabei unser Properties-Objekt von oben sowie ein neues Authenticator-Objekt als Argumente übergeben.
Der Code hinter new Authentificator() beschreibt eine sogenannte anonyme Klasse. "Anonym" deshalb, weil die Klasse keinen Namen hat und "mitten im Code" spontan erzeugt wird. Anonyme Klassen sind praktisch für eine einmalige Objekterzeugung "on the fly". Sie können Methoden von existierenden Klassen überschreiben - und genau das passiert hier auch.
Die Methode getPasswordAuthentication() liefert dann mit PasswordAuthentication eine gültiges Unterklassen-Objekt des benötigten Authenticator-Objekts zurück.
Message erstellen
Kommen wir nun zum Bau der eigentlichen Message. Dieser Vorang kann je nach Komplexität der abzuschickenden Nachricht mehr oder weniger umfangreich sein. Deshalb legen wir für die Message neue eigene Methode an, die wir prepareMessage() nennen:
private static Message prepareMessage(Session session, String myAccount, String empfaenger) throws Exception{
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(myAccount));
message.setRecipient(Message.RecipientType.TO, new InternetAddress(empfaenger));
message.setSubject("Mail Test");
// Multipart-Message ("Wrapper") erstellen
Multipart multipart = new MimeMultipart();
// Body-Part setzen:
BodyPart messageBodyPart = new MimeBodyPart();
// Textteil des Body-Parts
messageBodyPart.setText("Text-Inhalt der E-Mail zum Testen");
// Body-Part dem Multipart-Wrapper hinzufügen
multipart.addBodyPart(messageBodyPart);
// Message fertigstellen, indem sie mit dem Multipart-Content ausgestattet wird
message.setContent(multipart);
return message;
}
Die Methode nimmt in den Parametern das schon vorhandene Session-Objekt sowie Sender- und Empfänger-Adresse auf.
Innerhalb der Methode wird dann sogleich das MimeMessage-Objekt erstellt.
Anschließend werden mit drei Setter-Methoden für den Sender, Empfänger und den Betreff der Mail festgelegt.
Jetzt wird es spannend, denn wir basteln den Inhalt der E-Mail als Multipart-Nachricht. Der Multipart dient dabei als eine Art "Wrapper", dem die einzelnen Inhalts-Bestandteile, das sind die BodyPart-Objekte, hinzugefügt werden können.
Gegen Ende der Methode wird der vollständige Multipart der Message mit setContent() hinzugefügt. Die so fertiggebaute Message wird schließlich mit return zurückgeliefert.
Message mit Transport senden
Wir sind fast am Ziel!
Wir führen jetzt unsere eben erstellte prepareMessage()-Methode aus. Die durch die Methode gebastelte Message übergeben wir als Argument dem Transporter zum finalen Mail-Versand:
try {
Message message = prepareMessage(session, myAccount, empfaenger);
Transport.send(message);
System.out.println("E-Mail erfolgreich versendet!");
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Ab geht die Post 😁
Vollständiger Code
Hier noch der vollständige Code. Feel free to copy and paste:
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
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;
public class JavaMail {
private static Message prepareMessage(Session session, String myAccount, String empfaenger) throws Exception{
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(myAccount));
message.setRecipient(Message.RecipientType.TO, new InternetAddress(empfaenger));
message.setSubject("Mail Test");
// Multipart-Message ("Wrapper") erstellen
Multipart multipart = new MimeMultipart();
// Body-Part setzen:
BodyPart messageBodyPart = new MimeBodyPart();
// Textteil des Body-Parts
messageBodyPart.setText("Text-Inhalt der E-Mail zum Testen");
// Body-Part dem Multipart-Wrapper hinzufügen
multipart.addBodyPart(messageBodyPart);
// Message fertigstellen, indem sie mit dem Multipart-Content ausgestattet wird
message.setContent(multipart);
return message;
}
public static void main(String[] args) {
Properties properties = new Properties();
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.smtp.host", "smtp.gmail.com");
properties.put("mail.smtp.port", "587");
String myAccount = "marcus.algo@gmail.com";
String myPassword = "*********";
String empfaenger = "stefan.heller@falconbyte.net";
Session session = Session.getInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(myAccount, myPassword);
}
});
// Message-Objekt erzeugen und senden!
try {
Message message = prepareMessage(session, myAccount, empfaenger);
Transport.send(message); // E-Mail senden!
System.out.println("E-Mail erfolgreich versendet!");
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
Mail mit Datei-Anhang verschicken
Das Versenden vom Mails mit Anhang ist jetzt nur noch eine Kleinigkeit.
Wir fügen innerhalb der Methode prepareMessage() dem Multipart einfach einen weiteren BodyPart hinzu, der den Datei-Anhang modelliert:
BodyPart anhang = new MimeBodyPart();
String file = "beispieldatei.pdf";
DataSource source = new FileDataSource(file);
anhang.setDataHandler(new DataHandler(source));
anhang.setFileName(file);
multipart.addBodyPart(anhang);
message.setContent(multipart);
Thats' it!
JavaMail mit neuen Java-Versionen
Seit der Änderung von OracleJDK8 zu OpenJDK 11 funktioniert JavaMail nicht mehr ohne Weiteres und E-Mails können nicht mehr versandt werden. Eine java.lang.ClassNotFoundException wird geworfen:
java.lang.NoClassDefFoundError: javax/activation/DataSource (Abbreviation)
Caused by: java.lang.ClassNotFoundException: javax.activation.DataSource
Grund für die Exception ist, dass JavaMail das java.activation Package nutzt, das seit Java Version 11 aber aus der Standard-Bibliothek entfernt worden ist. Deshalb auch die ClassNotFoundException: Die darin enthaltenen Klassen können schlicht nicht gefunden werden.
Also holen wir uns das java.activation Paket, um unsere Mail-Anwendung zum Laufen zu bringen.
jar-Bibliothek einbinden
Wenn wir das Activation Framework in unser bestehendes Projekt einbinden, stehen die fehlenden Klassen wieder zur Verfügung. Dies kann über den klassischen jar-Bibliothekts-Import geschehen. Die jar-Datei gibt es hier oder bei uns zum Download.
Maven
Natürlich lässt sich das java.activation Paket auch über ein Maven Repository reinholen:
<dependency>
<groupId>com.sun.activation</groupId>
<artifactId>javax.activation</artifactId>
<version>1.2.0</version>
</dependency>
Sieh dir das auch als youtube-Tutorial an: