View Javadoc
1   package org.argeo.connect.mail;
2   
3   import java.util.Map;
4   import java.util.Properties;
5   
6   import javax.mail.Authenticator;
7   import javax.mail.Message;
8   import javax.mail.MessagingException;
9   import javax.mail.Multipart;
10  import javax.mail.PasswordAuthentication;
11  import javax.mail.Session;
12  import javax.mail.Transport;
13  import javax.mail.internet.InternetAddress;
14  import javax.mail.internet.MimeBodyPart;
15  import javax.mail.internet.MimeMessage;
16  import javax.mail.internet.MimeMultipart;
17  
18  import org.apache.commons.logging.Log;
19  import org.apache.commons.logging.LogFactory;
20  import org.argeo.connect.ConnectException;
21  import org.argeo.eclipse.ui.EclipseUiUtils;
22  
23  /** Sends a mail via JavaMail, local mail command or Google Mail. */
24  public class SendMail implements Runnable {
25  	private final static Log log = LogFactory.getLog(SendMail.class);
26  
27  	// See:
28  	// http://java.sun.com/developer/onlineTraining/JavaMail/contents.html#JavaMailUsage
29  	// http://java.sun.com/products/javamail/FAQ.html#gmail
30  
31  	// Configure mail sending via system properties
32  	// TODO Use a proper deployment configuration mechanism
33  	public final static String ARGEO_SEND_MAILS = "org.argeo.connect.mail.dosend";
34  	private final static String ARGEO_SMTP_TLS_DEBUG = "org.argeo.connect.smtp.tls.debug";
35  	private final static String DEFAULT_ENCODING = "UTF-8";
36  
37  	private final static boolean sendingActive = Boolean.parseBoolean(System.getProperty(ARGEO_SEND_MAILS, "true"));
38  
39  	private String host;
40  	private String port;
41  	private String from;
42  	private String to;
43  	private String subject;
44  	private String plainText;
45  	private String htmlText;
46  	private String username;
47  	private String password;
48  
49  	public void run() {
50  		// String doSend = System.getProperty(ARGEO_SEND_MAILS);
51  
52  		if (!sendingActive)
53  			traceUnsentMail();
54  		else {
55  			if ("smtp.gmail.com".equals(host))
56  				sendWithGMail();
57  			else
58  				sendWithJavaSmtp();
59  		}
60  	}
61  
62  	protected void sendWithJavaSmtp() {
63  
64  		// See
65  		// http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/javamail/javamail.html
66  		String doDebugStr = System.getProperty(ARGEO_SMTP_TLS_DEBUG);
67  		boolean debug = "true".equals(doDebugStr);
68  
69  		boolean auth = true;
70  		Properties props = new Properties();
71  		props.put("mail.smtp.host", host);
72  		props.put("mail.smtp.port", port);
73  		// To enable sending email without certificate, using port 25
74  		props.put("mail.smtp.starttls.enable", false);
75  		// To enable sending email with certificate, using port 587
76  		// props.put("mail.smtp.starttls.enable", true);
77  
78  		// switch (protocol) {
79  		// case SMTPS:
80  		// props.put("mail.smtp.ssl.enable", true);
81  		// break;
82  		// case TLS:
83  		// props.put("mail.smtp.starttls.enable", true);
84  		// break;
85  		// }
86  
87  		Authenticator authenticator = null;
88  		if (auth) {
89  			props.put("mail.smtp.auth", true);
90  			authenticator = new Authenticator() {
91  				private PasswordAuthentication pa = new PasswordAuthentication(username, password);
92  
93  				@Override
94  				public PasswordAuthentication getPasswordAuthentication() {
95  					return pa;
96  				}
97  			};
98  		}
99  		Session session = Session.getInstance(props, authenticator);
100 		session.setDebug(debug);
101 		MimeMessage message = new MimeMessage(session);
102 		try {
103 			buildJavaMailMessage(message);
104 			Transport.send(message);
105 		} catch (MessagingException ex) {
106 			throw new ConnectException("Unable to send java tls mail to " + to + " with username: " + username, ex);
107 		}
108 	}
109 
110 	protected void sendWithGMail() {
111 		try {
112 			Properties props = new Properties();
113 			props.put("mail.smtps.auth", "true");
114 			props.put("mail.smtps.host", host);
115 			props.put("mail.smtp.starttls.enable", true);
116 			Session session = Session.getDefaultInstance(props, null);
117 			MimeMessage message = new MimeMessage(session);
118 			buildJavaMailMessage(message);
119 			Transport t = session.getTransport("smtps");
120 			try {
121 				t.connect(host, username, password);
122 				t.sendMessage(message, message.getAllRecipients());
123 			} finally {
124 				t.close();
125 			}
126 			if (log.isDebugEnabled())
127 				log.debug("Sent mail to " + to + " with Google Mail");
128 		} catch (Exception e) {
129 			throw new ConnectException("Cannot send message.", e);
130 		}
131 	}
132 
133 	protected void buildJavaMailMessage(MimeMessage message) throws MessagingException {
134 		message.setFrom(new InternetAddress(from));
135 		InternetAddress toAddr = new InternetAddress(to);
136 		message.setRecipient(Message.RecipientType.TO, toAddr);
137 		message.setSubject(subject, DEFAULT_ENCODING);
138 		if (EclipseUiUtils.notEmpty((htmlText))) {
139 			Multipart multipart = new MimeMultipart("alternative");
140 			// Plain text
141 			MimeBodyPart textPart = new MimeBodyPart();
142 			textPart.setText(htmlText, DEFAULT_ENCODING);
143 			// Html formatted
144 			MimeBodyPart htmlPart = new MimeBodyPart();
145 			htmlPart.setText(htmlText, DEFAULT_ENCODING, "html");
146 			// Attach to message
147 			multipart.addBodyPart(textPart);
148 			multipart.addBodyPart(htmlPart);
149 			message.setContent(multipart);
150 		} else
151 			message.setText(plainText, DEFAULT_ENCODING);
152 	}
153 
154 	/**
155 	 * Shortcut to pass all data with only one call. We expect valid and non null
156 	 * strings for host, from, to, subject, text, username, password (See
157 	 * <code>MailProperty</code>
158 	 */
159 	public void setMailConfig(Map<String, String> mailConfig) {
160 		host = mailConfig.get(MailProperty.host.name());
161 		port = mailConfig.get(MailProperty.port.name());
162 		from = mailConfig.get(MailProperty.from.name());
163 		to = mailConfig.get(MailProperty.to.name());
164 		subject = mailConfig.get(MailProperty.subject.name());
165 		plainText = mailConfig.get(MailProperty.plainText.name());
166 		htmlText = mailConfig.get(MailProperty.htmlText.name());
167 		username = mailConfig.get(MailProperty.username.name());
168 		password = mailConfig.get(MailProperty.password.name());
169 	}
170 
171 	public void setHost(String host) {
172 		this.host = host;
173 	}
174 
175 	public void setFrom(String from) {
176 		this.from = from;
177 	}
178 
179 	public void setTo(String to) {
180 		this.to = to;
181 	}
182 
183 	public void setSubject(String subject) {
184 		this.subject = subject;
185 	}
186 
187 	public void setPlainText(String plainText) {
188 		this.plainText = plainText;
189 	}
190 
191 	public void setHtmlText(String htmlText) {
192 		this.htmlText = htmlText;
193 	}
194 
195 	public void setUsername(String username) {
196 		this.username = username;
197 	}
198 
199 	public void setPassword(String password) {
200 		this.password = password;
201 	}
202 
203 	private void traceUnsentMail() {
204 		StringBuilder builder = new StringBuilder();
205 		builder.append("*** MAIL NOT SENT *** ");
206 		builder.append("This message should have been sent but mail sending is disabled.\n");
207 		builder.append(logMail(false));
208 		log.info(builder.toString());
209 	}
210 
211 	public String logMail(boolean html) {
212 		StringBuilder builder = new StringBuilder();
213 		if (!html) {
214 			builder.append("From: ").append(from);
215 			builder.append(" - To: ").append(to);
216 			builder.append("- Subject: ").append(subject).append("\n");
217 			builder.append("Body: \n");
218 		}
219 		builder.append(html ? htmlText : plainText);
220 		return builder.toString();
221 	}
222 
223 	public static boolean isSendingActive() {
224 		return sendingActive;
225 	}
226 
227 }