# Emailsenden via Java Applikation



## KillerMeloneXY (5. Aug 2014)

Hallo,

ich habe mich jetzt so lange durchs diverse Seiten gelesen und Beispiele probiert (wovon keins funktionierte), dass ich nun komplett verwirrt bin.  Mein Code sieht folgendermaßen aus:

```
package com.engine;

import java.net.PasswordAuthentication;
import java.util.Properties;

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.MimeMessage;

public class EMail {
	public void sendeMail(String empfanger){
		String to = empfanger;
		String from = "senderadresse";
		
		Properties props = System.getProperties();
		props.put("mail.smtp.host", "securesmpt.freenet.de");
		props.put("mail.smtp.port", "465");
		props.put("mail.smtp.protocol", "smtps");
		props.put("mail.smtp.auth", "true");
		
		Session sess = Session.getDefaultInstance(props);
		
		MimeMessage mime = new MimeMessage(sess);
		try {
			mime.setFrom(new InternetAddress(from));
			mime.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
			mime.setSubject("This is Subject!");
			mime.setContent("<h1>Test test test</h1><br><p>Test 2</p>", "text/html");
			Transport.send(mime, from, "passwort");
			System.out.println("Success");
		} catch (MessagingException e) {
			e.printStackTrace();
		}
	}
}
```

Sender und das Passwort habe ich logischerweise rausgenommen (nur hier in meinem Post). Kann mir jemand erklären warum nun das Aufbauen der Verbindung mit einer MailConnectException schon beim Verbinden abbricht?

Hier die Exception:

com.sun.mail.util.MailConnectException: Couldn't connect to host, port: securesmpt.freenet.de, 465; timeout -1;
  nested exception is:
	java.net.ConnectException: Connection timed out: connect
	at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2053)
	at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:697)
	at javax.mail.Service.connect(Service.java:364)
	at javax.mail.Service.connect(Service.java:245)
	at javax.mail.Service.connect(Service.java:265)
	at javax.mail.Transport.send0(Transport.java:251)
	at javax.mail.Transport.send(Transport.java:174)
	at com.engine.EMail.sendeMail(EMail.java:32)
	at com.main.Starter.main(Starter.java:11)
Caused by: java.net.ConnectException: Connection timed out: connect
	at java.net.DualStackPlainSocketImpl.connect0(Native Method)
	at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
	at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
	at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
	at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
	at java.net.PlainSocketImpl.connect(Unknown Source)
	at java.net.SocksSocketImpl.connect(Unknown Source)
	at java.net.Socket.connect(Unknown Source)
	at java.net.Socket.connect(Unknown Source)
	at com.sun.mail.util.SocketFetcher.createSocket(SocketFetcher.java:312)
	at com.sun.mail.util.SocketFetcher.getSocket(SocketFetcher.java:236)
	at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2019)
	... 8 more

Soweit das die Verbindung auf Port sowieso nicht läuft habe ich verstanden...

Vlt. kann mir ja jemand helfen.
Btw.: Freenet nutzte ich nur weil es mein altes Postfach zum testen ist. Für GMX müsste ich dann auf normales SMTP umstellen und auf Port 587 oder?

Vielen Dank

Von der Klasse wird übrigens in einer anderen Klasse ein Objekt erstellt und sendeMail mit dem Empfänger aufgerufen.


----------



## Der Müde Joe (6. Aug 2014)

securesmpt? --> pt...wahscheinlich tp ;-)

EDIT:
Oder vielleicht auch net
Einstellungen (Serverdaten) fÃ¼r alle E-Mail ProgrammeÂ  - freenetMail-Hilfe


----------



## lawila (6. Aug 2014)

gut ... nehmen wir deinen code doch mal auseinander

zeile 18 : System.getProperties ? NEIN, man nimmt nicht die system-props sondern erzeugt ein neues Porperties-objekt
als ändern zu : [c]Properties props=new Properties();[/c]

zeile 19 : komplett falscher server-name
ist ja schön wenn du dir code aus den weiten des netzes zusammenklickst ... dabei solltest du aber vielleicht mal auch auf das alter dieser codes achten und dich mit den aktuellen daten des hosters bekannt machen
wie von Joe gepostet : mx.freenet.de

zeile 20 : SMTP/S TCP/465 ? klar, kann man machen wenn man alten SSLv2 standard nutzen will
ich würde dir jedoch dringend STMP/TLS TCP/587 empfehlen, ist deutlich sicherer

zeile 21/22 : fliegt komplett raus

zeile 24 : ja, man kann durch aus das singleton nutzen, würde ich aber nicht machen sondern mir mit Session.getInstance() arbeiten
außerdem fehlen hier login-daten : entweder in den properties (was ich nicht empfehlen würde) oder beim connect des Transport (was bei dir mal komplett fehlt)

zeile 32 : static Transport.send() ist ein absolutes NO-GO
du solltest dir mal die DOC dazu durchlesen



alles in allem ziemlich schlechter code der aus einer ur-alt quelle zusammen geklickt wurde

ein korrektes beispiel (schon angepasst auf freenet)


```
package mail;
import java.util.Properties;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
public class SendMailTLS
{
	public static void main(String[] args) throws Exception
	{
		String host="mx.freenet.de";
		int port=587;
		String user="USER@freenet.de";
		String pass="PASS";
		
		Properties props=new Properties();
		props.put("mail.smtp.starttls.enable", "true");
		
		Session session=Session.getInstance(props);
		Transport transport=session.getTransport("smtp");
		transport.connect(host, port, user, pass);

		Address[] addresses=InternetAddress.parse("recipient@domain.tld");
		
		Message message=new MimeMessage(session);
		message.setFrom(new InternetAddress(user));
		message.setRecipients(Message.RecipientType.TO, addresses);
		message.setSubject("TEST SUBJECT");

		message.setText("text/plain BODY");

		transport.sendMessage(message, addresses);
		System.out.println("SEND");

		transport.close();
	}
}
```

in zeile 25 wird der empfänger eingetragen
login-daten zeilen 15/16

btw zu deinem code : man nutzt nicht Message.setContent(String, String) sondern baut korrekt einen multipart-block mit entsprechendem encoding > mehr dazu in der DOC


----------



## KillerMeloneXY (7. Aug 2014)

Also gibt man dem Session Objekt die Einstellung mit tls true aus den Properties. Dann weißt man einem Transport Objekt die nötigen informationen aus der Session zu (mit getTransport für smtp). Mit dem Objekt eröffnet man dann eine Verbindung, die Ziel, Port, User und PW braucht. Und damit kann man dann arbeiten...

Habe ich das so richtig verstanden???

Und wenn ja, warum hat das Propertiesobjekt dann nur den einen Eintrag mit tls true?

Ansonsten schoneinmal danke!!! Es hat funktioniert.


----------



## lawila (7. Aug 2014)

ich hab das ganze mal lang und breit auf tutorials.de erklärt ... aber scheinbar haben die da auch aufgeräumt so das mein post leider nicht mehr existiert

aber ich erklär es gerne

gucken wir mal in die DOC : https://javamail.java.net/nonav/docs/api/
dort wird aufgelistet was alles in die props gepackt werden kann

mail.debug - debug-modus, gibt zusätzliche informationen auf System.out aus und eignet sich um die kommunikation mit dem server weiter zu analysieren ... hilfreich wenn zwar eine verbindung hergestellt werden kann, die mail aber warum auch immer trotzdem nicht versand wird (wobei mögliche exceptions trotzdem auf System.err landen)

mail.from - absender-adresse, hat eigentlich keine praktische bedeutung da ein korrekt konfigurierter MTA eine mail nur dann versendet wenn vom client der FROM-header korrekt gesetzt wird (siehe dazu zeile 28 in meinem code) bzw wird vom server automatisch korrigiert wenn fehlerhaft oder komplett fehlend
auf den möglichen missbrauch bei einem fehlerhaft konfigurierten MTA gehe ich nicht weiter ein

mail.mime.address.strict - strict-modus für adressen-parsing (erlich gesagt keine ahnung was das ist, default ist true)

mail.host - host-adresse, macht eigentlich nicht wirklich sinn da bei den meisten mail-providern für die einzelnen dienste (imap, pop3 und smtp) verschiedene dns genutzt werden und man daher eigentlich mail._protocol_.host nutzt, würde aber hier im freenet-beispiel funktionieren (beachte kursive schreibweise von protocol > wird durch gewünschtes protokoll (imap/s, pop3/s, smtp/s) ersetzt)

mail.store.protocol - protokoll für e-mail download, hier kann man vorgeben welches protokoll für den download genutzt wird, also pop3/s oder imap/s und würde sich so die angabe bei Session.getStore() sparen

mail.transport.protocol - analog zu mail.store.protocol nur für den upload

mail.user - user-name

mail._protocol_.class - bestimmte service-klasse für _protocol_, java-mail arbeitet nach dem factory-pattern, über diese option kann man angeben welche bestimmte service-klasse zu laden ist, normalerweise nicht weiter wichtig so das die standard-klassen geladen werden

mail._protocol_.host - wie mail.host, nur das man hier halt bestimmt für _protocol_ den host angibt, also z.b. für ein smtp halt smtp.freenet.de oder für imap halt imap.freenet.de (beispiel, für freenet wie gesagt korrekt : mx.freenet.de)

mail._protocol_.port - port für _protocol_, normalerweise eigentlich nicht wirklich weiter wichtig da es für smtp, pop3 und imap fest definierte standard-ports gibt, aber man kann ja auch davon abweichen (wobei TCP/25 für SMTP halt grundsätzlich immer sein muss für die inter-server-verbindung um mails auch empfangen zu können)

mail._protocol_.user - user für _protocol_, ich muss zwar zugeben ich hab noch nie gesehen das sich die login-daten für versnd (smtp) und abruf (pop3/imap) unterscheiden, aber möglich ist das mit sicherheit


was auffällt : nirgends wird die möglichkeit gegeben in das props-objekt ein kennwort zu packen
ist auch richtig so, denn das ist der jeweiligen connect-methode grundsätzlich immer direkt zu übergeben

was weiter auffällt : hier fehlt doch so einiges wie z.b. mail._protocol_.starttls und ähnliches, warum ?
das liegt daran das diese optionen dann schon protokoll- und implementierungs-abhängig sind

die sun-implementierung com.sun.mail.smtp z.b. unterstützt noch eine ganze reihe an weiteren optionen, wie eben z.b. mail.smtp.starttls oder andere
aber : das ist nur das was die sun-implementierung kann und nicht vorgeschrieben ist das das auch andere können müssen

welcher properties-parameter also unterstützt werden (das gilt auch für die oberen die ich erklärt habe) ist immer davon abhängig welche implementierung man benutzt

nutzt man die sun-implementierung gelten auch alle in der doc genannten optionen, nutzt man eine andere muss man in dessen doc gucken was für optionen gültig sind


so, warum gibt es jetzt so viele props-möglichkeiten die ich in meinem code nicht nutze ?
die erklärung ist relativ simpel : es gibt bei java-mail nun mal zwei wege nach rom

der eine weg ist das man alle gewünschten infos in das props-objekt packt und dann mit dem singleton und den static methoden arbeitet, dabei ziehen sich alle methoden die nötigen informationen aus dem props-objekt und verarbeiten diese
der andere ist das man den entsprechenden methoden die gewünschten werte alle einzeln als parameter übergibt


was bedeuten jetzt diese "zwei wege" konkret ?
nun, eigentlich nicht viel mehr und weniger als das man halt anstatt alles als parameter zu übergeben auch alles in ein props-objekt packen kann und sich die methoden die werte selbst rauslesen



was hat es jetzt mit Transport.send() auf sich ?

nun, guckt man sich die doc an wird man feststellen das alle Transport.send() methoden static sind
bedeutet : das man man, wie in deinem code wunderschön zu sehen, eigentlich gar kein Transport-objekt braucht um darüber selbst die verbindung zu steuern, das wird intern von Transport.send() automatisch gemacht

was ist aber der unterschied ?

nun, als einer der haupt-unterschied würde ich schon mal sagen : wenn man mehrere mails hat baut man ein mal eine verbindung auf und lässt dann darüber alle mails laufen (sehr sinnvoll wenn man in einem client wie gesagt mehrere mails auf einmal senden will ... oder natürlich auch ganz sinnvoll beim empfang ... wobei beim empfang ein Transport-objekt definitiv nötig ist)

weiterhin : man kann den verbindungs-fluss selbst noch mal ein wenig steuern

der haupt-grund ist aber folgender :


> Note that send is a static method that creates and manages its own connection. Any connection associated with any Transport instance used to invoke this method is ignored and not used. This method should only be invoked using the form Transport.send(msg);, and should never be invoked using an instance variable.



was genau bedeutet das ? nun, es beudetet das hier sehr viel "rückwärts" gearbeitet wird

um das schema zu veranschaulichen

man steckt erst alles in das props-objekt
baut sich ne session
auf diese session ne message
und callt dann warum auch immer Transport.send()

so, man merkt eigentlich gleich : kann doch gar nicht funktionieren, Transport hat doch gar keine infos ... oder ?
antwort : DOCH, und zwar rückwärts

Transport holt sich also aus der message die session, daraus die props und liest dieses aus

das ist ein unglaublich aufwändiger call-stack und ist gegen multi-threading null gesichert


das wiederspricht dann auch irgendwie so ein bisschen dem was man sich davor alles mühsam aufgebaut hat und lässt die frage aufkommen : warum so kompliziert ? dann gebt uns doch gleich eine methode in der wir alles als parameter reindrücken können


naja, halte ich persönlich für ein ziemliches design-flaw und würde immer auf eine saubere verbindung über Transport.sendMessage() gehen


----------



## KillerMeloneXY (7. Aug 2014)

Ahh, ok

das macht Sinn...

Vielen Dank habe keine Fragen mehr und schließe deswegen hier!

Vielen Dank nochmal!!


----------

