package com.alimama.mdrill.adhoc; import java.io.PrintStream; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.net.Socket; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.Properties; import java.util.StringTokenizer; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.InitialDirContext; import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.log4j.Logger; public class SendMail { private static Logger LOG = Logger.getLogger(SendMail.class); private final static String DATE_TEMPLET = "d MMM yyyy HH:mm:ss Z";//"EEE, d MMM yyyy HH:mm:ss Z"; //"Sat, 12 Sep 2009 20:52:10 +0800" private final static String BOUNDARY_PREFIX = "--"; private final static String CRLF = "\r\n"; private Socket socket; private BufferedReader input; private PrintStream output=null; private SimpleDateFormat format; public SendMail() {} public static void main(String[] args) throws Exception { SendMail send=new SendMail(); send.send("adhoc@alipay.com","adhoc",args[0], args[0],args[1],args[2],"", "gbk", "172.24.108.36","172.24.108.36","","", 25); } public void send(String to,String subject,String content,String attachment,String charset) { send(to,subject,content,attachment,charset,"",""); } public void send(String to,String subject,String content,String attachment,String charset,String user,String pass) { String[] toList=to.split("[,|;]+"); for(String tostr:toList) { try { String[] addressList= getSMTPServerByJNDI(tostr); for(int i=0;i<addressList.length;i++) { Boolean result=false; String[] fromlist={"yannian.mu@alipay.com","myn@163.com","165162897@qq.com"}; //这样做是有些服务器,堆特定网站的邮箱进行了校验,有可能会失败 for(String from:fromlist) { result=send(from,"yannian",tostr, to,subject,content,attachment, charset, addressList[i],addressList[i],user,pass, 25); if(result) { break; } } if(result) { break; } } } catch (Exception e) {} } } public void send(String from,String formName,String to,String subject,String content,String attachment,String charset,String user,String pass) { String[] toList=to.split("[,|;]+"); for(String tostr:toList) { try { String[] addressList= getSMTPServerByJNDI(tostr); for(int i=0;i<addressList.length;i++) { Boolean result=send(from,formName,tostr, to,subject,content,attachment, charset, addressList[i],addressList[i],user,pass, 25); if(result) { break; } } } catch (Exception e) {} } } private String getDomainFromAddress( String EmailAddress ) { StringTokenizer tokenizer = new StringTokenizer( EmailAddress, "@>;" ); String DomainOnly = tokenizer.nextToken(); DomainOnly = tokenizer.nextToken(); return DomainOnly; } private String[] getSMTPServerByJNDI(String to) throws Exception { String host=getDomainFromAddress(to); Properties jndiEnvironmentProperties = new Properties(); jndiEnvironmentProperties.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory"); InitialDirContext initialDirContext = new InitialDirContext(jndiEnvironmentProperties); Attributes attributes = initialDirContext.getAttributes(host, new String[] {"MX"}); Attribute attribute = attributes.get("MX"); String[] servers = new String[attribute.size()]; for (int i = 0; i < attribute.size(); i++) { servers[i] = attribute.get(i).toString(); servers[i]=servers[i].substring(servers[i].indexOf(" ") + 1, servers[i].length() -1); } return servers; } public boolean send(String from,String formName,String to,String replyTO,String subject,String content,String attachment,String charset,String smtpAddress,String smtpHost,String user,String pass,int port) { try { String boundary = "=======ThisIsBoundary======="; socket = new Socket(); socket.setSoTimeout(10000); socket.connect(new InetSocketAddress(smtpAddress, port));// input = new BufferedReader( new InputStreamReader( socket.getInputStream() ) ); output = new PrintStream( socket.getOutputStream() ); getResponse( "220", "Failed to connect to: " + smtpHost, true ); sendCommand( "HELO " + smtpHost/*NO SPACE IN IT*/ + CRLF); getResponse( "250", "Failed to get HELO response from server.", true ); if(user!=null && !user.isEmpty() && pass!=null && !pass.isEmpty()) { sendCommand( "AUTH LOGIN" + CRLF ); getResponse( "334", "Failed to get USERNAME request from server.", true ); sendCommand( getBase64String( user ) + CRLF ); //Username getResponse( "334", "Failed to get PASSWORD request from server.", true ); sendCommand( getBase64String( pass ) + CRLF ); //Password getResponse( "235", "Failed to send AUTH LOGIN username and password to server.", true ); } sendCommand( "MAIL FROM: <" + from + ">" + CRLF ); getResponse( "250", "Failed to get MAIL FROM response from server.", true ); String[] toList=to.split("[,|;]+"); for(String tostr:toList) { sendCommand( "RCPT TO: <" + tostr + ">" + CRLF ); getResponse( "250", "Failed to get RCPT TO response from server.", false/*NOTE*/ ); } if(replyTO==null||replyTO.isEmpty()) { replyTO=to; } sendCommand( "DATA" + CRLF ); getResponse( "354", "Failed to get DATA response from server.", true ); sendCommand( "Subject: " + getBase64Subject( subject, charset ) + CRLF ); sendCommand( "Date: " + getDateString() + CRLF ); sendCommand( "From: " + ""+formName+"<" + from + ">" + CRLF ); sendCommand( "To: " +replyTO + CRLF ); sendCommand( "MIME-Version: 1.0" + CRLF ); sendCommand( "Content-Type: multipart/mixed; boundary=\"" + boundary + "\"" + CRLF ); sendCommand( "Content-Transfer-Encoding: 7bit" + CRLF + CRLF/*NOTE*/ ); sendCommand( "This is a multi-part message in MIME format." + CRLF + CRLF/*NOTE*/ ); sendCommand( BOUNDARY_PREFIX + boundary + CRLF ); sendCommand( "Content-Type: text/html;" + CRLF ); sendCommand( "Content-Transfer-Encoding: base64" + CRLF + CRLF/*NOTE*/ ); sendCommand( getBase64String( content, charset ) + CRLF + CRLF/*NOTE*/ ); String[] fileList=attachment.split("[ |\t|,]+"); for(String eachFile:fileList){ if(eachFile.trim().isEmpty()) { continue; } sendCommand( BOUNDARY_PREFIX + boundary + CRLF ); String [] filenamesplit=eachFile.split("[\\\\|/]+"); String filename=filenamesplit[filenamesplit.length-1]; if(eachFile.startsWith("hdfs@")&&filename.indexOf(".")<0) { filename+=".txt"; } sendCommand( "Content-Type: application/octet-stream; name=\"" + filename + "\"" + CRLF ); sendCommand( "Content-Transfer-Encoding: base64" + CRLF ); sendCommand( "Content-Disposition: attachment; filename=\"" + filename + "\"" + CRLF + CRLF/*NOTE*/ ); sendAttachment( eachFile ); } sendCommand( CRLF + "." + CRLF/*NOTE*/ ); //Indicate the end of date using "/r/n./r/n" getResponse( "250", "Failed to send DATA content to server.", true ); sendCommand( "QUIT" + CRLF ); getResponse( "221", "Failed to get QUIT response from server.", true ); LOG.info("succ "+from+" to "+to+" "+smtpAddress); return true; } catch( Exception e ){ e.printStackTrace(); LOG.info("fail "+from+" to "+to+" "+smtpAddress); return false; } finally{ try{ output.close(); input.close(); socket.close(); }catch( Exception e ){} } } private void sendAttachment( String fileName ) throws Exception { FileInputStream inputStream = new FileInputStream( fileName ); int base64PerLine = 76; //76 base64 charactors per line int charsPerLine = 57; //57 = 76 / 4 * 3 byte[] src = new byte[4096]; byte[] dest = new byte[src.length * 2]; int length = 0, remain = 0, sOffset = 0, dOffset = 0; int maxlength=1024*1024; int readlean=0; while( ( length = inputStream.read( src, remain, src.length - remain ) ) != -1 ) { readlean+=length; length = length + remain; remain = length % charsPerLine; length = length / charsPerLine * charsPerLine; for( sOffset = 0, dOffset = 0; sOffset < length; ) { Base64Encode.encode( src, sOffset, charsPerLine, dest, dOffset ); sOffset += charsPerLine; dOffset += base64PerLine; dest[dOffset ++] = '\r'; dest[dOffset ++] = '\n'; } output.print( new String( dest, 0, dOffset ) ); if( remain > 0 ){ System.arraycopy( src, sOffset, src, 0, remain ); } if(readlean>maxlength) { break; } } if( remain > 0 ) { Base64Encode.encode( src, 0, remain, dest, 0 ); dOffset = ( remain + 2 ) / 3 * 4; dest[dOffset ++] = '\r'; dest[dOffset ++] = '\n'; output.print( new String( dest, 0, dOffset ) ); } inputStream.close(); } private void sendCommand( String command ) throws Exception { if( output == null || command == null || command.length() < 1 ){ return ; } output.print( command ); } private void getResponse( String code, String message, boolean shouldQuit ) throws Exception { if( input == null || code == null || code.length() < 1 ){ return; } String line = input.readLine(); if( line.startsWith( code ) ){ /**/ }else if( shouldQuit ){ System.out.println(line); throw new Exception( message ); } } private String getBase64String( String message ) { if( message == null ){ return null; } byte[] bytes = message.getBytes(); return Base64Encode.encode( bytes, 0, bytes.length ); } private String getBase64String( String subject, String charset ) { if( subject == null ){ return null; } byte[] bytes = null; try{ bytes = ( charset == null ? subject.getBytes() : subject.getBytes( charset ) ); }catch( Exception e ){ } return ( bytes == null ? null : Base64Encode.encode( bytes, 0, bytes.length )); } private String getBase64Subject( String subject, String charset ) { if( subject == null ){ return null; } byte[] bytes = null; try{ bytes = ( charset == null ? subject.getBytes() : subject.getBytes( charset ) ); }catch( Exception e ){ } return ( bytes == null ? null : "=?" + charset + "?B?" + Base64Encode.encode( bytes, 0, bytes.length ) + "?=" ); } private String getDateString() { if( format == null ){ try{ format = new SimpleDateFormat( DATE_TEMPLET, Locale.ENGLISH ); }catch( Exception e ){} } return ( format == null ? new Date().toString() : format.format( new Date() ) ); } }