Il codice seguente funziona molto bene con il server SMTP di Google. È necessario fornire il nome utente e la password di Google.
import com.sun.mail.smtp.SMTPTransport;
import java.security.Security;
import java.util.Date;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
/**
*
* @author doraemon
*/
public class GoogleMail {
private GoogleMail() {
}
/**
* Send email using GMail SMTP server.
*
* @param username GMail username
* @param password GMail password
* @param recipientEmail TO recipient
* @param title title of the message
* @param message message to be sent
* @throws AddressException if the email address parse failed
* @throws MessagingException if the connection is dead or not in the connected state or if the message is not a MimeMessage
*/
public static void Send(final String username, final String password, String recipientEmail, String title, String message) throws AddressException, MessagingException {
GoogleMail.Send(username, password, recipientEmail, "", title, message);
}
/**
* Send email using GMail SMTP server.
*
* @param username GMail username
* @param password GMail password
* @param recipientEmail TO recipient
* @param ccEmail CC recipient. Can be empty if there is no CC recipient
* @param title title of the message
* @param message message to be sent
* @throws AddressException if the email address parse failed
* @throws MessagingException if the connection is dead or not in the connected state or if the message is not a MimeMessage
*/
public static void Send(final String username, final String password, String recipientEmail, String ccEmail, String title, String message) throws AddressException, MessagingException {
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
// Get a Properties object
Properties props = System.getProperties();
props.setProperty("mail.smtps.host", "smtp.gmail.com");
props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
props.setProperty("mail.smtp.socketFactory.fallback", "false");
props.setProperty("mail.smtp.port", "465");
props.setProperty("mail.smtp.socketFactory.port", "465");
props.setProperty("mail.smtps.auth", "true");
/*
If set to false, the QUIT command is sent and the connection is immediately closed. If set
to true (the default), causes the transport to wait for the response to the QUIT command.
ref : http://java.sun.com/products/javamail/javadocs/com/sun/mail/smtp/package-summary.html
http://forum.java.sun.com/thread.jspa?threadID=5205249
smtpsend.java - demo program from javamail
*/
props.put("mail.smtps.quitwait", "false");
Session session = Session.getInstance(props, null);
// -- Create a new message --
final MimeMessage msg = new MimeMessage(session);
// -- Set the FROM and TO fields --
msg.setFrom(new InternetAddress(username + "@gmail.com"));
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipientEmail, false));
if (ccEmail.length() > 0) {
msg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(ccEmail, false));
}
msg.setSubject(title);
msg.setText(message, "utf-8");
msg.setSentDate(new Date());
SMTPTransport t = (SMTPTransport)session.getTransport("smtps");
t.connect("smtp.gmail.com", username, password);
t.sendMessage(msg, msg.getAllRecipients());
t.close();
}
}
Aggiornamento l'11 dicembre 2015
Nome utente e password non sono più una soluzione consigliata. Questo è dovuto a
Ho provato questo e Gmail ha inviato all'email utilizzata come nome utente in questo codice un'e-mail dicendo che abbiamo recentemente bloccato un tentativo di accesso al tuo account Google e mi ha indirizzato a questa pagina di supporto: support.google.com/accounts/answer/6010255 quindi cerca che funzioni, l'account di posta elettronica utilizzato per l'invio deve ridurre la propria sicurezza
Google aveva rilasciato l'API Gmail - https://developers.google.com/gmail/api/?hl=en . Dovremmo usare il metodo oAuth2, invece di nome utente + password.
Ecco lo snippet di codice per lavorare con l'API di Gmail.
GoogleMail.java
import com.google.api.client.util.Base64;
import com.google.api.services.gmail.Gmail;
import com.google.api.services.gmail.model.Message;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Properties;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
/**
*
* @author doraemon
*/
public class GoogleMail {
private GoogleMail() {
}
private static MimeMessage createEmail(String to, String cc, String from, String subject, String bodyText) throws MessagingException {
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
MimeMessage email = new MimeMessage(session);
InternetAddress tAddress = new InternetAddress(to);
InternetAddress cAddress = cc.isEmpty() ? null : new InternetAddress(cc);
InternetAddress fAddress = new InternetAddress(from);
email.setFrom(fAddress);
if (cAddress != null) {
email.addRecipient(javax.mail.Message.RecipientType.CC, cAddress);
}
email.addRecipient(javax.mail.Message.RecipientType.TO, tAddress);
email.setSubject(subject);
email.setText(bodyText);
return email;
}
private static Message createMessageWithEmail(MimeMessage email) throws MessagingException, IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
email.writeTo(baos);
String encodedEmail = Base64.encodeBase64URLSafeString(baos.toByteArray());
Message message = new Message();
message.setRaw(encodedEmail);
return message;
}
public static void Send(Gmail service, String recipientEmail, String ccEmail, String fromEmail, String title, String message) throws IOException, MessagingException {
Message m = createMessageWithEmail(createEmail(recipientEmail, ccEmail, fromEmail, title, message));
service.users().messages().send("me", m).execute();
}
}
Per creare un servizio Gmail autorizzato tramite oAuth2, ecco lo snippet di codice.
Utils.java
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.gmail.Gmail;
import com.google.api.services.gmail.GmailScopes;
import com.google.api.services.oauth2.Oauth2;
import com.google.api.services.oauth2.model.Userinfoplus;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.yccheok.jstock.engine.Pair;
/**
*
* @author yccheok
*/
public class Utils {
/** Global instance of the JSON factory. */
private static final GsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
/** Global instance of the HTTP transport. */
private static HttpTransport httpTransport;
private static final Log log = LogFactory.getLog(Utils.class);
static {
try {
// initialize the transport
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
} catch (IOException ex) {
log.error(null, ex);
} catch (GeneralSecurityException ex) {
log.error(null, ex);
}
}
private static File getGmailDataDirectory() {
return new File(org.yccheok.jstock.gui.Utils.getUserDataDirectory() + "authentication" + File.separator + "gmail");
}
/**
* Send a request to the UserInfo API to retrieve the user's information.
*
* @param credentials OAuth 2.0 credentials to authorize the request.
* @return User's information.
* @throws java.io.IOException
*/
public static Userinfoplus getUserInfo(Credential credentials) throws IOException
{
Oauth2 userInfoService =
new Oauth2.Builder(httpTransport, JSON_FACTORY, credentials).setApplicationName("JStock").build();
Userinfoplus userInfo = userInfoService.userinfo().get().execute();
return userInfo;
}
public static String loadEmail(File dataStoreDirectory) {
File file = new File(dataStoreDirectory, "email");
try {
return new String(Files.readAllBytes(Paths.get(file.toURI())), "UTF-8");
} catch (IOException ex) {
log.error(null, ex);
return null;
}
}
public static boolean saveEmail(File dataStoreDirectory, String email) {
File file = new File(dataStoreDirectory, "email");
try {
//If the constructor throws an exception, the finally block will NOT execute
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
try {
writer.write(email);
} finally {
writer.close();
}
return true;
} catch (IOException ex){
log.error(null, ex);
return false;
}
}
public static void logoutGmail() {
File credential = new File(getGmailDataDirectory(), "StoredCredential");
File email = new File(getGmailDataDirectory(), "email");
credential.delete();
email.delete();
}
public static Pair<Pair<Credential, String>, Boolean> authorizeGmail() throws Exception {
// Ask for only the permissions you need. Asking for more permissions will
// reduce the number of users who finish the process for giving you access
// to their accounts. It will also increase the amount of effort you will
// have to spend explaining to users what you are doing with their data.
// Here we are listing all of the available scopes. You should remove scopes
// that you are not actually using.
Set<String> scopes = new HashSet<>();
// We would like to display what email this credential associated to.
scopes.add("email");
scopes.add(GmailScopes.GMAIL_SEND);
// load client secrets
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(Utils.JSON_FACTORY,
new InputStreamReader(Utils.class.getResourceAsStream("/assets/authentication/gmail/client_secrets.json")));
return authorize(clientSecrets, scopes, getGmailDataDirectory());
}
/** Authorizes the installed application to access user's protected data.
* @return
* @throws java.lang.Exception */
private static Pair<Pair<Credential, String>, Boolean> authorize(GoogleClientSecrets clientSecrets, Set<String> scopes, File dataStoreDirectory) throws Exception {
// Set up authorization code flow.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, JSON_FACTORY, clientSecrets, scopes)
.setDataStoreFactory(new FileDataStoreFactory(dataStoreDirectory))
.build();
// authorize
return new MyAuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
}
public static Gmail getGmail(Credential credential) {
Gmail service = new Gmail.Builder(httpTransport, JSON_FACTORY, credential).setApplicationName("JStock").build();
return service;
}
}
Per fornire un modo intuitivo di autenticazione oAuth2, ho utilizzato JavaFX per visualizzare la seguente finestra di dialogo di input
La chiave per visualizzare la finestra di dialogo oAuth2 di facile utilizzo può essere trovata in MyAuthorizationCodeInstalledApp.java e SimpleSwingBrowser.java