EmailValidator.getInstance().isValid("some.mail.address@gmail.com");Make sure to add the Commons Validator jar file and it's dependencies to your project.
Software development and photography related issues
EmailValidator.getInstance().isValid("some.mail.address@gmail.com");Sometimes we would like to send emails that have better looking and are more rich in their content. Today’s most email clients know to show HTML email content. That means that the body of the email is actually HTML rather than plain text. Sending HTML emails is quite simple and can be done using Apache Commons Email. Here is an example class built on Apache Commons Email that sends HTML email:
package com.bashan.blog.mail;import org.apache.commons.mail.EmailException;import org.apache.commons.mail.HtmlEmail;public class Mailer {protected String host;protected String username = null;protected String password = null;protected boolean isTLS = false;public Mailer(String host, String username, String password, boolean isTLS) {this.host = host;this.username = username;this.password = password;this.isTLS = isTLS;}public Mailer(String host, String username, String password) {this(host, username, password, false);}public Mailer(String host) {this(host, null, null, false);}public void sendHTMLMail(String fromEmail,String fromName,String[] toEmail,String[] toName,String subject,String html,String alternateText) throws EmailException {HtmlEmail email = new HtmlEmail();email.setHostName(host);email.setFrom(fromEmail, fromName);for (int i = 0; i < toEmail.length; i++) {email.addTo(toEmail[i], toName[i]);}if (username != null) {email.setAuthentication(username, password);}email.setTLS(isTLS);email.setSubject(subject);email.setHtmlMsg(html);email.setTextMsg(alternateText);email.send();}}
In order to use this code, make sure to put “commons-email.jar” as well as “mail.jar” (Java mail) in your class path. The latest version of “mail.jar” can be easily found by searching “java mail” in Google and downloading from Sun web site.
Note that the method “sendHTMLMail” contains property named: “alternateText”. This property is used for mail clients that does not support receiving HTML mails.
Suppose we would like to make our HTML email look better and add some image to it. We don’t want the image to be sent as a regular attachment. We would like the image to be embedded in our HTML mail message by using the image tag (img).
Luckily, Apache Commons Email supplies a simple way of doing it by using the “embed” method. For example, in order to embed an image that is placed in some URL we can do:
String id = email.embed(new URL("http://server.com/someimage.png"), "Example");
Note that “embed” method takes 2 arguments. First is the URL pointing to the image location and second is the image name. Note also that the “embed” method returns a String id. This id is used as a reference to the image embedded in the mail message. For example, our HTML mail message can look like:
email.setHtmlMsg("<html><body><image src='cid:" + id + "'></body></html>");Note that the embedded image is referenced by using the prefix: “cid:” in the image “src” property.
As you can see, the embed method returns an id that is being later used in the construction of the HTML. this makes it a bit harder embedding images in HTML mail messages, since we don’t know the id of the embedded image when passing the HTML code as an argument. We can easily solve this problem by defining our own convention of referencing the embedded images that will later will be replaced with the proper id. Our convention will be: Each embed resource which we would like to embed in our HTML code will be named:
${resource number}For example, suppose we would like to embed a single image. our HTML code will look like:
<html><body><img src='${0}' /></body></html>Where the: ${0} means, we would like to put our first image in the “src” property.
Support we have 2 images that we want to use 4 times in our HTML. For example:
<html><body><img src='${0}' /><img src='${1}' /><img src='${0}' /><img src='${1}' /></body></html>
In this example we want to embed in our HTML 2 images and show them one after another twice. Of course that in the code, we will make sure to replace all the occurrences with: ${resource number} with the proper id of the embedded image.
Since an embedded resource is actually defined by 2 parameters: URL and name, we will define an inner static class that will represent a resource. This class is named: Resource. The class is pretty straight forward and need no explanations. An array of this class will be used for passing our method as many resources as we would like to embed in our HTML mail message. Of course that the “resource number” signifies the position of the resource we would like to embed in our Resources array. For example: “${3}” means we would like to embed the 4th resource from our resources array.
We can now have a look at our complete “sendHTMLMail” method that also knows to send multiple embedded resources along with the HTML mail message. Note that the old method for sending HTML mails without resources is still supported:
package com.bashan.blog.mail;import org.apache.commons.mail.EmailException;import org.apache.commons.mail.HtmlEmail;import java.net.MalformedURLException;import java.net.URL;public class Mailer {protected String host;protected String username = null;protected String password = null;protected boolean isTLS = false;public Mailer(String host, String username, String password, boolean isTLS) {this.host = host;this.username = username;this.password = password;this.isTLS = isTLS;}public Mailer(String host, String username, String password) {this(host, username, password, false);}public Mailer(String host) {this(host, null, null, false);}public void sendHTMLMail(String fromEmail,String fromName,String[] toEmail,String[] toName,String subject,String html,String alternateText,Resource[] resources) throws EmailException {HtmlEmail email = new HtmlEmail();email.setHostName(host);email.setFrom(fromEmail, fromName);for (int i = 0; i < toEmail.length; i++) {email.addTo(toEmail[i], toName[i]);}if (username != null) {email.setAuthentication(username, password);}if (resources != null) {int i = 0;for (Resource resource : resources) {String id = email.embed(resource.getUrl(), resource.getName());html = html.replaceAll("\\$\\{" + i++ + "\\}", "cid:" + id);}}email.setTLS(isTLS);email.setSubject(subject);email.setHtmlMsg(html);email.setTextMsg(alternateText);email.send();}public void sendHTMLMail(String fromEmail,String fromName,String[] toEmail,String[] toName,String subject,String html,String alternateText) throws EmailException {sendHTMLMail(fromEmail, fromName, toEmail, toName, subject, html, alternateText, null);}public static class Resource {private URL url;private String name;public Resource(URL url, String name) {this.url = url;this.name = name;}public Resource(String url, String name) throws MalformedURLException {this(new URL(url), name);}public URL getUrl() {return url;}public void setUrl(URL url) {this.url = url;}public String getName() {return name;}public void setName(String name) {this.name = name;}}public static void main(String[] args) throws Exception {new Mailer("smtp.gmail.com", "youruser@gmail.com", "yourpassword", true).sendHTMLMail("admin@test.com", "Tester", new String[]{"guy.bashan@gmail.com"}, new String[]{"Guy Bashan"}, "Testing HTML Email","<html><body><table><tr><td>Image 1</td><td>Image 2</td></tr><tr><td>" +"<img src='${0}'/></td><td><img src='${1}'/></td></tr></table></body></html>", "alternate HTML",new Resource[]{new Resource("http://www.google.com/intl/en_ALL/images/logo.gif", "Google Logo 1"),new Resource("http://www.google.com/intl/en_ALL/images/logo.gif", "Google Logo 2")});}}
In the bottom of the Mailer class you can find a small test program that sends HTML mail message with 2 embed images of Google logo.
props.put("mail.smtp.starttls.enable","true");Where props is a simple Property instance containing mail properties.But, as was said before, we have no access to the Properties instance, and therefore cannot add the TLS property.Session session = Session.getInstance(props);
Luckily, SMTPAppender does contain a protected method, for getting the Session instance: createSession. We can override this method and create a Session instance that contains TLS support. I copied the code of this method exactly as it was on the original SMTPAppender, and simply added the TLS property (note that TLS support is added only if user actually use the TLS property in the appender definition). This is how the class BaseFilteredSMTPAppender looks after adding the TLS support:
import org.apache.log4j.net.SMTPAppender;import javax.mail.Authenticator;import javax.mail.PasswordAuthentication;import javax.mail.Session;import java.util.*;public abstract class BaseFilteredSMTPAppender extends SMTPAppender {private int timeFrame;private int maxEMails;protected long timeFrameMillis;protected Boolean isTLS;protected List<Date> exceptionDates = new ArrayList<Date>();public int getTimeFrame() {return timeFrame;}public void setTimeFrame(int timeFrame) {this.timeFrame = timeFrame;}public int getMaxEMails() {return maxEMails;}public void setMaxEMails(int maxEMails) {this.maxEMails = maxEMails;}public void setTLS(boolean isTLS) {this.isTLS = isTLS;}@Overridepublic void activateOptions() {super.activateOptions();timeFrameMillis = timeFrame * 60 * 1000;}@Overrideprotected Session createSession() {Properties props = null;try {props = new Properties (System.getProperties());} catch(SecurityException ex) {props = new Properties();}if (getSMTPHost() != null) {props.put("mail.smtp.host", getSMTPHost());}Authenticator auth = null;if(getSMTPUsername() != null && getSMTPPassword() != null) {props.put("mail.smtp.auth", "true");auth = new Authenticator() {protected PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication(getSMTPUsername(), getSMTPPassword());}};}if (isTLS != null && isTLS){props.put("mail.smtp.starttls.enable","true");}Session session = Session.getInstance(props, auth);if (getSMTPDebug()) {session.setDebug(getSMTPDebug());}return session;}protected void cleanTimedoutExceptions() {Date current = new Date();// Remove timedout exceptionsIterator<Date> itr = exceptionDates.iterator();while (itr.hasNext()) {Date exceptionDate = itr.next();if (current.getTime() - exceptionDate.getTime() > timeFrameMillis) {itr.remove();} else {break;}}}protected void addException() {exceptionDates.add(new Date());}protected boolean isSendMailAllowed() {return exceptionDates.size() < maxEMails;}}
In order to make things a little interesting I will show you log4j configuration example using XML file instead of properties file:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"><log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false"><appender name="console" class="org.apache.log4j.ConsoleAppender"><param name="Target" value="System.out"/><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern" value="%d{HH:mm:ss,SSS} %-5p [%c{1}] %m%n"/></layout></appender><appender name="email" class="com.bashan.log4j.appender.FilteredSMTPAppender"><param name="BufferSize" value="10"/><param name="SMTPHost" value="smtp.gmail.com"/><param name="SMTPUsername" value="username@gmail.com"/><param name="SMTPPassword" value="password"/><param name="TLS" value="true"/><param name="TimeFrame" value="10"/><param name="MaxEMails" value="2"/><param name="From" value="username@gmail.com"/><param name="To" value="anotherUsername@gmail.com"/><param name="Subject" value="Server Error"/><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern" value="%d{HH:mm:ss,SSS} %-5p [%c{1}] %m%n"/></layout></appender><root><priority value="warn"/><appender-ref ref="console"/><appender-ref ref="email"/></root></log4j:configuration>
Note that TLS property is not mandatory. If you don't need TLS support, you can simply not add it to the appender properties.
In the post “Sending Email alerts with Log4j” and in the post “Sending Email alerts with Log4j – Controlled Alerts” I wrote about a simple way of sending email alerts using the ready log4j appender SMTPAppender. But, there are times in which an organization wants to send system alerts directly to a cell phone, in order to be notified about a problem as soon as possible.
ipipi.com is SMS service allowing sending SMS messages to almost every cell phone in the world. There is a support for sending SMS messages over SMTP protocol. Extending log4j SMTP appender to send SMS alert messages is easy task.
There is only one thing important to notice: Sending error message as SMS has to be much shorter than sending email. SMS messages can have very few characters. For this reason log4j SMTP appender has to be altered in order to send only the error string written to the log and the first line from the exception stack trace. This is done in the following class: FilteredShortSMTPAppender. Note that this class extends BaseFilteredSMTPAppender from the post “Sending Email alerts with Log4j – Controlled Alerts”:
import org.apache.log4j.spi.LoggingEvent;import org.apache.log4j.helpers.LogLog;import java.util.Date;import javax.mail.Multipart;import javax.mail.Transport;import javax.mail.internet.MimeMultipart;import javax.mail.internet.MimeBodyPart;public class FilteredShortSMTPAppender extends BaseFilteredSMTPAppender {@Overridepublic void activateOptions(){super.activateOptions();setBufferSize(1);}@Overrideprotected void sendBuffer() {cleanTimedoutExceptions();if (isSendMailAllowed()) {try {MimeBodyPart part = new MimeBodyPart();StringBuffer sbuf = new StringBuffer();String t = layout.getHeader();if (t != null) {sbuf.append(t);}LoggingEvent event = cb.get();sbuf.append(layout.format(event));if (layout.ignoresThrowable()) {String[] s = event.getThrowableStrRep();if (s != null && s.length > 0) {sbuf.append(s[0]);}t = layout.getFooter();}if (t != null) {sbuf.append(t);}part.setContent(sbuf.toString(), layout.getContentType());Multipart mp = new MimeMultipart();mp.addBodyPart(part);msg.setContent(mp);msg.setSentDate(new Date());Transport.send(msg);addException();}catch (Exception e) {LogLog.error("Error occured while sending e-mail notification.", e);}}}}
The class FilteredShortSMTPAppender allows to send email alerts in a short version. It can be used exactly the same as FilteredSMTPAppender, besides the parameter: BufferSize is no longer needed, since we do not send log history with the mail message.
After we have the class FilteredShortSMTPAppender we can easily extend it to send SMS email alerts over SMTP using the ipipi.com service:
Note that the information regarding the ipipi.com service is on external file named ipipi.properties. This file should be located on the same package as the IPIPISmsOverSmtpAppender class:import org.apache.log4j.helpers.LogLog;import java.io.IOException;import java.util.Properties;public final class IPIPISmsOverSmtpAppender extends FilteredShortSMTPAppender {private static final String KEY_HOST = "host";private static final String TO_SERVER = "to.server";private String toServer;@Overridepublic void activateOptions() {Properties properties = new Properties();try {properties.load(IPIPISmsOverSmtpAppender.class.getResourceAsStream("ipipi.properties"));setSMTPHost(properties.getProperty(KEY_HOST));setFrom(getSMTPUsername() + "@" + getSMTPHost());toServer = properties.getProperty(TO_SERVER);setTo(parseAddress(getTo()));}catch (IOException ioe) {LogLog.error("Failed loading IPIPI service properties", ioe);}super.activateOptions();}private String parseAddress(String addressStr) {String[] addresses = addressStr.split(",");StringBuffer sb = new StringBuffer();for (String address : addresses) {sb.append(address).append("@").append(toServer).append(",");}return sb.substring(0, sb.length() - 1);}}
This class extends the capabilities of the class FilteredShortSMTPAppender to allow adding cell phone numbers instead of email addresses. In your appender configuration file you can simply insert cell phone numbers and this code will know to convert the cell phone numbers to email addresses used for ipipi.com convention. The service allows sending SMS message to almost any cell phone on the planet by using the cell phone owner as the email address prefix. for example, you can simply send SMS message to a cell phone by emailing to: 972541234567@ipipi.com. Of course, that the service costs money, and in order to send SMS messages you must first register to the service and buy a package of SMS messages. Your registered username and password is used as login details for ipipi.com SMTP server.host=ipipi.comto.server=sms.ipipi.com
This is an example of the IPIPISmsOverSmtpAppender log4j configuration:
Note for few things:log4j.rootLogger=INFO, a, smslog4j.appender.a=org.apache.log4j.ConsoleAppenderlog4j.appender.a.layout=org.apache.log4j.PatternLayoutlog4j.appender.a.layout.ConversionPattern=%d{HH:mm:ss} %-5p [%c{1}]: %m%nlog4j.appender.sms=com.bashan.log4j.IPIPISmsOverSmtpAppenderlog4j.appender.sms.SMTPUsername=bashanlog4j.appender.sms.SMTPPassword=bashanlog4j.appender.sms.TimeFrame=10log4j.appender.sms.MaxEMails=30log4j.appender.sms.To=972541234567,972542345678log4j.appender.sms.layout=org.apache.log4j.PatternLayoutlog4j.appender.sms.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n