Powered By Blogger

Wednesday, June 22, 2011

Email attachment downloader

This simple java program uses java mail to connect to a pop mail server and reads inbox, iterates through the inbox messages and then downloads the message attachments if any.

Steps:
1. Make a session with aunthenticator
2. Get the Store and call store the connect.
3. Get the folder "INBOX" from the store and open it for read and write.
4. Read the attachement Part by part.getInputStream()
5. write the read bytes to the output file stream

Some properties values to be used:
a. user : name of the user on the email server like abc.kk@abcmail.com
b. password : user's passoword for authentication
c. protocol : pop3 or any other protocol for reading mails
d. attachment : directory location for attachment downloads




public void doEMailDownload( ) throws Exception {
// Create empty properties
// Properties props = new Properties();

Properties props = new Properties();

// Get the session
// Session session = Session.getInstance(props, null);
Session session = Session.getDefaultInstance(props,
new javax.mail.Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication( receiving_user, receiving_pass );
}
});

// Get the store
Store store = session.getStore(receiving_protocol);
store.connect(receiving_host, receiving_user, receiving_pass);

// Get folder
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_WRITE);

try {

// Get directory listing
Message messages[] = folder.getMessages();
EmailPolicy emailPolicy = new EmailPolicy();

for (int i=0; i < messages.length; i++) {
// get the details of the message:
EMail email = new EMail();

email.subject = messages[i].getSubject();

/* filter Email Inbox as per some download policy */

if ( ! emailPolicy.checkAllPolicies( messages[i] ) ) {
continue;
}

email.fromaddr = messages[i].getFrom()[0].toString();
Address[] to = messages[i].getRecipients(Message.RecipientType.TO);
email.toaddr = "";
for(int j = 0; j < to.length; j++){
email.toaddr += to[j].toString() + "; ";
}
Address[] cc;
try {
cc = messages[i].getRecipients(Message.RecipientType.CC);
} catch (Exception e){
System.out.println("Exception retrieving CC addrs: %s" + e.getLocalizedMessage());
cc = null;
}
email.cc = "";
if(cc != null){
for(int j = 0; j < cc.length; j++){
email.cc += cc[j].toString() + "; ";
}
}
email.subject = messages[i].getSubject();
if(messages[i].getReceivedDate() != null){
email.received_when = messages[i].getReceivedDate().getTime();
} else {
email.received_when = new java.util.Date().getTime();
}


email.body = "";
Vector vema = new Vector();
Object content = messages[i].getContent();
if(content instanceof java.lang.String){
email.body = (String)content;
} else if(content instanceof Multipart){
Multipart mp = (Multipart)content;

for (int j=0; j < mp.getCount(); j++) {
Part part = mp.getBodyPart(j);

String disposition = part.getDisposition();

if (disposition == null) {
// Check if plain
MimeBodyPart mbp = (MimeBodyPart)part;
if (mbp.isMimeType("text/plain")) {

email.body += (String)mbp.getContent();
} else {
// Special non-attachment cases here of
// image/gif, text/html, ...
EMailAttach ema = new EMailAttach();
ema.name = decodeName(part.getFileName());

if ( ! isAllowedAttachment( ema.name ) ) continue;

File savedir = new File(receiving_attachments);
if ( savedir.exists() ) {
savedir.mkdirs();
}
//File savefile = File.createTempFile("emailattach", ".atch", savedir );
File savefile = new File( savedir, ema.name );
ema.path = savefile.getAbsolutePath();
ema.size = part.getSize();
vema.add(ema);
ema.size = saveFile(savefile, part);
}
} else if ((disposition != null) &&
(disposition.equals(Part.ATTACHMENT) || disposition.equals(Part.INLINE) )
){
// Check if plain
MimeBodyPart mbp = (MimeBodyPart)part;
if (mbp.isMimeType("text/plain")) {
System.out.println("Mime type is plain");
email.body += (String)mbp.getContent();
} else {
System.out.println("Save file (%s)" + part.getFileName() );
EMailAttach ema = new EMailAttach();
ema.name = decodeName(part.getFileName());
File savedir = new File(receiving_attachments);
savedir.mkdirs();
//File savefile = File.createTempFile("emailattach", ".atch", savedir );
File savefile = new File( savedir, ema.name );
ema.path = savefile.getAbsolutePath();
ema.size = part.getSize();
vema.add(ema);
ema.size = saveFile( savefile, part);
}
}
}
}


// Finally delete the message from the server.
//messages[i].setFlag(Flags.Flag.DELETED, true);
}

// Close connection
folder.close(true); // true tells the mail server to expunge deleted messages.
store.close();
} catch (Exception e){
folder.close(true); // true tells the mail server to expunge deleted messages.
store.close();
throw e;
}

}

public static class EMail {
public String fromaddr;
public String toaddr;
public String cc;
public String subject;
public long received_when;
public String body;
}

/**
*
*/
public static class EMailAttach {
public String name;
public String path;
public int size;
}

/**
*
* @param saveFile
* @param part
* @return
* @throws Exception
*/
protected int saveFile(File saveFile, Part part) throws Exception {

BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream(saveFile) );

byte[] buff = new byte[2048];
InputStream is = part.getInputStream();
int ret = 0, count = 0;
while( (ret = is.read(buff)) > 0 ){
bos.write(buff, 0, ret);
count += ret;
}
bos.close();
is.close();
return count;
}

protected String decodeName( String name ) throws Exception {
if(name == null || name.length() == 0){
return "unknown";
}
String ret = java.net.URLDecoder.decode( name, "UTF-8" );

// also check for a few other things in the string:
ret = ret.replaceAll("=\\?utf-8\\?q\\?", "");
ret = ret.replaceAll("\\?=", "");
ret = ret.replaceAll("=20", " ");

return ret;
}

Wednesday, May 12, 2010

Live Email Validation

Basically there are 3 steps to validate whether a email is real.
1. Simple regex validation like presence of a '@' character
2. Validate the Dns
3. Actually ping the email server to see if the user is listed

Here's a simple java utility that does all the above 3 steps.

__________________________________________________________________________________________________

import java.io.*;
import java.net.*;
import java.util.*;
import javax.naming.*;
import javax.naming.directory.*;

import org.apache.log4j.Logger;

/**
* SMTP look for live email validation
*
* @author nitesh.kumar
*
*/
public class LiveEmailValidator {

private static Logger log = Logger.getLogger( LiveEmailValidator.class );

private static DirContext dirContext = null;

static {
if ( dirContext == null ) {
Hashtable env = new Hashtable();
env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
try {
dirContext = new InitialDirContext( env );
} catch (NamingException e) {
log.error( "naming exception while initialising dir context.", e );
}
}
}

/**
*
* @return
*/
static DirContext getDirContext() {
return dirContext;
}

/**
*
* @param address
* @return
*/
public static boolean isAddressValid ( String address ) {
Response res = null;
for ( int i = 0; i < EMAILValidationConstants.MAX_COUNT; i++ ) {
res = validateOnce( address );

if ( res == null ) {
return false;
}
int code = res.code;
if ( code < 400 || code >= 500 ) {
break;
}
try {
Thread.sleep( 60 * EMAILValidationConstants.TIME_TO_SLEEP_IN_MIN * 1000 );
} catch (InterruptedException e) {
e.printStackTrace();
}
}

System.out.println( "code :" + res.code + " . message : " + res.message );
return ( res.code == 250 ) ? true : false;
}

/**
*
* @author nitesh.kumar
*
*/
private static class Response {
int code;
String message;

public Response(int code, String message) {
this.code = code;
this.message = message;
}
}

/**
*
* @param code
* @param message
* @return
*/
private static Response getResponse( int code ) {
return new Response( code, SMTPReplyCodes.getMessage( code ) ) ;
}

/**
*
* @param code
* @param message
* @return
*/
private static Response getResponse( int code, String message ) {
return new Response( code, message ) ;
}

/**
*
* @param address
* @return
*/
public static Response validateOnce( String address ) {
int code = -1;
int pos = address.indexOf( '@' );
if ( pos == -1 ) {
return getResponse( -1 );
}

String domain = address.substring( ++pos );
ArrayList mxList = null;
try {
mxList = DNSValidator.getMX( domain );
}
catch (NamingException ex) {
return getResponse( SMTPReplyCodes.DNS_VALIDATION_FAILED, ex.getMessage() );
}

if ( mxList.size() == 0 ) {
return getResponse( SMTPReplyCodes.DNS_VALIDATION_FAILED );
}

for ( int mx = 0 ; mx < mxList.size() ; mx++ ) {
boolean valid = false;
Socket skt = null;
BufferedReader rdr = null;
BufferedWriter wtr = null;
Response res = null;
try {

skt = new Socket( mxList.get( mx ), 25 );
rdr = new BufferedReader( new InputStreamReader( skt.getInputStream() ) );
wtr = new BufferedWriter( new OutputStreamWriter( skt.getOutputStream() ) );

code = doValidationSteps( rdr, wtr, address );
resetAndQuit( rdr, wtr );

if ( code != 250 ) {
throw new Exception( "Address " + address + " is not valid!" );
}
valid = true;
res = getResponse( code );
}
catch (Exception ex) {
log.error( "Exception while validating email :" + address, ex );
}
finally {

if ( log.isDebugEnabled() ) {
StringBuilder sb = new StringBuilder();
sb.append ( "validating email : ")
.append( address )
.append( valid ? " .Address is VALID" : " . Address is not VALID" );
log.debug( sb.toString() );
}
close( rdr, wtr, skt);
if ( valid ) {
return res != null ? res : getResponse( code );
}
}
}
return getResponse( code );
}

/**
*
* @param rdr
* @param wtr
* @param skt
* @throws IOException
*/
private static void close( BufferedReader rdr, BufferedWriter wtr, Socket skt ) {
try {
if ( rdr != null ) rdr.close();
if ( wtr != null ) wtr.close();
if ( skt != null ) skt.close();
} catch ( IOException io ) {
log.error( "error while closing streams", io );
}
}

/**
*
* @param rdr
* @param wtr
* @return
* @throws EMAILValidationException
* @throws IOException
*/
private static int doValidationSteps( BufferedReader rdr, BufferedWriter wtr, String addressToValidate ) throws EMAILValidationException, IOException {
int res = SMTPValidator.validateHeader( rdr );

res = SMTPValidator.requestMailAction( rdr, wtr, EMAILValidationConstants.SENDER_HOST );

res = SMTPValidator.validateSender( rdr, wtr, EMAILValidationConstants.SENDER_ADDRESS );

res = SMTPValidator.validateActualAddress( rdr, wtr, addressToValidate );

return res;
}

/**
* reset and quit smtp validation
* @param rdr
* @param wtr
* @return
* @throws EMAILValidationException
* @throws IOException
*/
private static int resetAndQuit( BufferedReader rdr, BufferedWriter wtr ) throws EMAILValidationException, IOException {
int res = SMTPValidator.reset( rdr, wtr );

res = SMTPValidator.quit( rdr, wtr );
return res;
}

public static void main( String args[] ) {
String testData[] = {
"nitesh.kumar@gmail.com"
};

for ( int ctr = 0 ; ctr < testData.length ; ctr++ ) {
System.out.println( testData[ ctr ] + " is valid? " +
LiveEmailValidator.isAddressValid( testData[ ctr ] ) );
}
return;
}
}

/**
*
* @author nitesh.kumar
*
*/
class SMTPReplyCodes {

public static final int DNS_VALIDATION_FAILED = 100;

public static final int SYSTEM_STATUS = 211;
public static final int HELP_MESSAGE = 214;
public static final int DOMAIN_SERVICE_READY = 220;
public static final int OK_QUERYONG_FOR_NODE_NODE_STARTED = 250;
public static final int DOMAIN_SERVICE_NOT_AVAILABE = 421;
public static final int REQUEST_ACTION_ABORTED = 451;

public static final String UNKNOWN_ERROR = "UNKNOWN ERROR";

private static HashMap map;
static {
if ( map == null ) {
map = new HashMap();

map.put( Integer.valueOf(-1), "ADDRESS DOES NOT SATISFY BASIC REGEX VALIDATION" );
map.put( Integer.valueOf( SYSTEM_STATUS ), "SYSTEM STATUS" );
map.put( Integer.valueOf( HELP_MESSAGE ), "HELP MESSAGE" );
map.put( Integer.valueOf( OK_QUERYONG_FOR_NODE_NODE_STARTED ), "OK QUERYONG FOR NODE NODE STARTED" );
map.put( Integer.valueOf( DOMAIN_SERVICE_NOT_AVAILABE ), "DOMAIN SERVICE NOT AVAILABE" );
map.put( Integer.valueOf( DOMAIN_SERVICE_READY ), "DOMAIN SERVICE READY" );

map.put( Integer.valueOf( REQUEST_ACTION_ABORTED ), "REQUEST ACTION ABORTED" );
map.put( Integer.valueOf( DNS_VALIDATION_FAILED ), "DNS VALIDATION FAILED" );
}
}

public static String getMessage( int code ) {
String msg = map.get( Integer.valueOf( code ) );
if ( msg != null ) {
return msg;
}
if ( code >= 400 && code < 500 ) {
return map.get( Integer.valueOf( REQUEST_ACTION_ABORTED ) );
}
return UNKNOWN_ERROR;
}


}

/**
*
* @author nitesh.kumar@a3logics.in
*
*/
class EMAILValidationConstants {

public static final String SENDER_HOST = "google.com";
public static final String SENDER_ADDRESS = "nitesh.iitr@gmail.com";

public static final int MAX_COUNT = 2;
public static final int TIME_TO_SLEEP_IN_MIN = 2;
}

/**
*
* @author niitesh.kumar@a3logics.in
*
*/
class SMTPValidator {

public SMTPValidator() {
//
}

/**
*
* @param rdr
* @return
* @throws EMAILValidationException
* @throws IOException
*/
public static int validateHeader( BufferedReader rdr ) throws EMAILValidationException, IOException {
int res = hear( rdr );
if ( res != SMTPReplyCodes.DOMAIN_SERVICE_READY ) throw new EMAILValidationException( "Invalid header" );
return res;
}

/**
*
* @param rdr
* @param wtr
* @param toPing
* @return
* @throws EMAILValidationException
* @throws IOException
*/
static int requestMailAction( BufferedReader rdr, BufferedWriter wtr, String toPingHost ) throws EMAILValidationException, IOException {

say( wtr, "EHLO " + toPingHost );

int res = hear( rdr );
if ( res != SMTPReplyCodes.OK_QUERYONG_FOR_NODE_NODE_STARTED ) throw new EMAILValidationException( "Not ESMTP" );
return res;
}

/**
*
* @param rdr
* @param wtr
* @param senderAddress
* @return
* @throws EMAILValidationException
* @throws IOException
*/
static int validateSender( BufferedReader rdr, BufferedWriter wtr, String senderAddress ) throws EMAILValidationException, IOException {

say( wtr, getMAILFROMStr( senderAddress ) );
int res = hear( rdr );
if ( res != SMTPReplyCodes.OK_QUERYONG_FOR_NODE_NODE_STARTED ) throw new EMAILValidationException( "Sender rejected" );
return res;
}

/**
*
* @param rdr
* @param wtr
* @return
* @throws EMAILValidationException
* @throws IOException
*/
static int reset( BufferedReader rdr, BufferedWriter wtr ) throws EMAILValidationException, IOException {

say( wtr, "RSET" );
return hear( rdr );
}

/**
*
* @param rdr
* @param wtr
* @return
* @throws IOException
*/
static int quit( BufferedReader rdr, BufferedWriter wtr ) throws IOException {

say( wtr, "QUIT" );
return hear( rdr );
}

/**
*
* @param actualAddressToPing
* @return
*/
private static String getRCPTOStr( String actualAddressToPing ) {
StringBuilder sb = new StringBuilder();
sb.append( "RCPT TO: <" )
.append( actualAddressToPing )
.append ( ">" );
return sb.toString();
}

/**
*
* @param in
* @return
* @throws IOException
*/
private static int hear( BufferedReader in ) throws IOException {
String line = null;
int res = 0;

while ( (line = in.readLine()) != null ) {
String pfx = line.substring( 0, 3 );
try {
res = Integer.parseInt( pfx );
}
catch (Exception ex) {
res = -1;
}
if ( line.charAt( 3 ) != '-' ) break;
}

return res;
}

/**
*
* @param wr
* @param text
* @throws IOException
*/
private static void say( BufferedWriter wr, String text ) throws IOException {
wr.write( text + "\r\n" );
wr.flush();

return;
}

/**
*
* @param rdr
* @param wtr
* @param actualAddressToPing
* @return
* @throws EMAILValidationException
* @throws IOException
*/
static int validateActualAddress( BufferedReader rdr, BufferedWriter wtr, String actualAddressToPing ) throws EMAILValidationException, IOException {
say( wtr, getRCPTOStr( actualAddressToPing ) );
int res = hear( rdr );
return res;
}

/**
*
* @param senderAddress
* @return
*/
private static String getMAILFROMStr( String senderAddress ) {
StringBuilder sb = new StringBuilder();
sb.append( "MAIL FROM: <" )
.append( senderAddress )
.append ( ">" );
return sb.toString();
}
}

/**
*
* @author nitesh.kumar
*
*/
class DNSValidator {

DNSValidator() {
//
}

/**
*
* @param hostName
* @return
* @throws NamingException
*/
static ArrayList getMX( String hostName ) throws NamingException {

DirContext ictx = LiveEmailValidator.getDirContext();
if ( ictx == null ) {
throw new NamingException( "naming exception while initialising dir context." );
}
Attributes attrs = ictx.getAttributes( hostName, new String[] { "MX" } );
Attribute attr = attrs.get( "MX" );

if (( attr == null ) || ( attr.size() == 0 )) {
attrs = ictx.getAttributes( hostName, new String[] { "A" });
attr = attrs.get( "A" );
if( attr == null ) {
throw new NamingException( "No match for name '" + hostName + "'" );
}
}

ArrayList res = new ArrayList(5);
NamingEnumeration en = attr.getAll();

while ( en.hasMore() ) {
String mailhost;
String x = ( String ) en.next();
String f[] = x.split( " " );

if (f.length == 1)
mailhost = f[0];
else if ( f[1].endsWith( "." ) )
mailhost = f[1].substring( 0, (f[1].length() - 1));
else
mailhost = f[1];

res.add( mailhost );
}
return res;
}

}

/**
*
* @author nitesh.kumar
*
*/
class EMAILValidationException extends Exception {

/**
*
*/
private static final long serialVersionUID = -507597264595246045L;

EMAILValidationException() {
super();
}

public EMAILValidationException( String msg ) {
super ( msg );
}
}