Thursday, November 12, 2009

GMail and log4j e-mail appender - error STARTTLS

I couldn't get log4j working along with Google. I kept on getting the following error:

com.sun.mail.smtp.SMTPSendFailedException: 530 5.7.0 Must issue a STARTTLS


Later I found out that the best way to get it working was creating my own SMTP appender. What I wanted, was to have a flexible application that I could configure once with a gmail username (marcelo@gmail) and then have the users/clients configure the rest of the log4j appender using the log4j property file.

Below is how I created the application. First you will need your parameters for your gmail account including the starttls. I place all these in a Enum class.

public enum EmailEnum {
HOST(
"smtp.googlemail.com"), PORT("587"),
USERNAME(
"marcelo@gmail.com"),PASSWORD("secret"),
AUTHORIZED(
"mail.smtp.auth"), STARTTTS("mail.smtp.starttls.enable"),
TRUE(
"true");
private String value;
private EmailEnum(String value) {
this.value = value;
}

public String getValue() {
return value;
}
}


Then, I created the class that actually creates the mail appender. The main part is the appender method. As you can see, I am using the SMTPAppender class and I override the appender method. As you can tell, I'm using the Spring SimpleMail class to send the message.


package com.upmobile.midccore.commons.logger;

import java.util.Properties;

import org.apache.log4j.net.SMTPAppender;
import org.apache.log4j.spi.LoggingEvent;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;


/**
* Application builds the SMPT Appender for the Google Mail (gmail).
*
@author marceloolivas
*
*/
public class GMailAppender extends SMTPAppender {
private JavaMailSenderImpl javaMail;
private static final String NL = System.getProperty("line.separator");

public GMailAppender() {
javaMail
= new JavaMailSenderImpl();
javaMail.setHost(EmailEnum.HOST.getValue());
javaMail.setPort(Integer.parseInt(EmailEnum.PORT.getValue()));
javaMail.setUsername(EmailEnum.USERNAME.getValue());
javaMail.setPassword(EmailEnum.PASSWORD.getValue());
Properties props
= new Properties();
props.setProperty(EmailEnum.AUTHORIZED.getValue(), EmailEnum.TRUE.getValue());
props.setProperty(EmailEnum.STARTTTS.getValue(), EmailEnum.TRUE.getValue());
javaMail.setJavaMailProperties(props);

}

@Override
public void append(LoggingEvent event) {
super.append(event);
// Create a thread safe "copy" of the template message and customize it
SimpleMailMessage msg = new SimpleMailMessage();
StringBuilder builder
= new StringBuilder();
builder.append(getLayout().format(event));
builder.append(event.getMessage().toString());
if (event.getThrowableInformation() != null) {
builder.append(NL);
String[] stackTrace
= event.getThrowableInformation().getThrowableStrRep();
for(int i = 0; i < stackTrace.length; i++) {
builder.append(stackTrace[i]
+ NL);
}
msg.setText(builder.toString());
}
String[] senders
= getTo().trim().replace(" ", "").split(",");
msg.setTo(senders);
msg.setSubject(
this.getSubject());
try{
javaMail.send(msg);
}
catch (MailException ex){
}

}
}


The actual log4j properties file is the following:

# Global logging configuration
log4j.rootLogger
=ERROR, stdout, EMAIL
# SqlMap logging configuration...
log4j.logger.com.ibatis
=DEBUG
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource
=DEBUG
log4j.logger.com.ibatis.sqlmap.engine.cache.CacheModel
=DEBUG
log4j.logger.com.ibatis.sqlmap
=DEBUG
log4j.logger.com.ibatis.sqlmap.engine.builder.xml.SqlMapParser
=DEBUG
log4j.logger.com.ibatis.common.util.StopWatch
=DEBUG
log4j.logger.java.sql.Connection
=DEBUG
log4j.logger.java.sql.Statement
=DEBUG
log4j.logger.java.sql.PreparedStatement
=DEBUG
log4j.logger.java.sql.ResultSet
=DEBUG

log4j.logger.org.springframework
=INFO
log4j.logger.com.upmobile
=DEBUG
# Console output...
log4j.appender.stdout
=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout
=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern
=%-4p [%d{ISO8601}][%t] (%c.%M()line %-4L ) %m%n

# e
-mail appender
log4j.appender.EMAIL
=com.upmobile.midccore.commons.logger.GMailAppender
log4j.appender.EMAIL.Threshold
=ERROR
log4j.appender.EMAIL.Subject
=Error with the application
log4j.appender.EMAIL.to
=abc@acme.com,xyz@acme.commons
log4j.appender.EMAIL.SMTPDebug
=true
log4j.appender.EMAIL.layout
=org.apache.log4j.PatternLayout
log4j.appender.EMAIL.layout.ConversionPattern
=[%d] [%t] %-5p %c %x - %m%n
log4j.appender.EMAIL.BufferSize
=1

2 comments:

  1. I've really appreciated this code..
    But I got a problem with the duration while sending email.
    I used System.currentTimeMills.
    It took 7 second for each mail.
    How could I try to fix it?

    ReplyDelete
  2. If the problem in loading Gmail account still continues you must get in touch with Gmail Customer Support. As there is nothing more you can do on your part to eliminate this problem. https://www.buzzfeed.com/jiprinojit/gmail-support-services-to-resolve-2hmtt

    ReplyDelete