不需要smtp服务器的邮件发送

原创 2012年03月10日 15:57:06
工作中总用到需要发送邮件的情形,但是每次都需要一个smtp服务器来转发,他们仅仅是转发而已
为了一个简单的邮件还要弄个邮件服务器太麻烦了,Postfix不会装,sendmail也不熟悉。
而且如果公司的邮件服务器不稳定(别说你没碰到),总是能遇到邮件发送延迟,甚至丢失的情况
干嘛不自己伪造个协议,跳过通过smtp服务器这一层呢?而且可以模拟任何人给任何人发送邮件(虽然可以,但是鄙视发垃圾邮件的人)。

如果你的邮件地址是a@host.com,而你要用这个邮箱发送一封邮件到to@tohost.com,你需要连接到服务器host.com上,当然这个连接可能需要认证,现在基本上都要验证,然后是发送邮件到服务器host.com上,关闭连接。在host.com上,你所发送的邮件进入发送队列中,轮到你要发送的邮件时,host.com主机再联系tohost.com,将邮件传输到服务器tohost.com上。


//这段是我转载的
首先我们看一下Email的递送过程:
Email(Encode) -> a SMTP Relay Server  -> Remote SMTP Server(远程邮局)。
非常简单,邮件编码后被递送到一个SMTP转交服务器上,该服务器对信件分检
(到同一邮局的被放在一起)后,根据优先级以及信件的先后次序被发送到远程
邮局的SMTP服务器上。换句话说,只要我们知道了SMTP转交服务器是如何确定远
程邮局SMTP服务器的地址的,就可以轻松地将饶开SMTP Relay Server直接递送
到远程邮局服务器。
  SMTP Relay Server是如何确定远程邮局服务器的地址的呢?如果你熟悉域名解
析,就知道是怎么回事了,我们知道电子邮件的地址由两部分构成postbox@address.com,
邮箱(postbox)和地址(address.com),给域名服务器发送指令查询“address.com”
的远程邮局服务器的地址即可找到远程邮局SMTP服务器的IP 地址,该指令查询是
被称作MX(Mail Exchange)邮件交换服务器的地址查询。远程邮局SMTP服务器的地
址可能不止一个,这时,你可根据信件优先级的不同,将对应优先级的信件发到
对应地址的远程邮局SMTP服务器,当然,你也可以不管三七二十一,随便选一个
SMTP服务器发送,见后附“域名解析结果样例”。简单吧。这下,自己编写一个
SMTP Server不难了吧!

废话少说,这个寻找smtp relay server 的过程不需要我们来弄,JAVA里线程的
 
    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; 
    }


########当然还算要贴完整的代码的=================
package libtools.util;
import java.io.PrintStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
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 libtools.tar.TarFsPublic;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;



public class SendMail
{
    private static final Logger log = LoggerFactory.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("myn@163.com,165162897@qq.com,yannian.mu@alipay.com", "我的测试", "正文内容", "", "utf8", "", "");
    }
   
   
    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( smtpAddress, port/*COMMON*/ );
            socket.setSoTimeout(10000);
            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/plain;" + CRLF );
            sendCommand( "Content-Transfer-Encoding: base64" + CRLF + CRLF/*NOTE*/ );
            sendCommand( getBase64String( content ) + 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 );
            System.out.println("succ "+from+" to "+to+"    "+smtpAddress);

            return true;
        }
        catch( Exception e ){
            System.out.println("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
    {
       if(fileName.startsWith("hdfs@"))
       {
           sendHDFSAttachment(fileName.replaceAll("hdfs@", ""));
           return ;
       }
       
        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;
        while( ( length = inputStream.read( src, remain, src.length - remain ) ) != -1 )
        {
            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( 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 sendHDFSAttachment( String fileName ) throws Exception
    {
        FileSystem fs=TarFsPublic.getFileSystem();
        FSDataInputStream inputStream = fs.open(new Path(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;
        while( ( length = inputStream.read( src, remain, src.length - remain ) ) != -1 )
        {
            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( 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 ){ 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 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 ){
            log.error("libtools",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 ){log.error("libtools",e);} }

        return ( format == null ? new Date().toString() : format.format( new Date() ) );
    }

  
}

通过SMTP SERVER 无需身份验证发送邮件

建立SMTP服务器发送匿名邮件   1.       系统:Windows XP/2000   2.       安装设置服务端     Windows XP和2000本身就拥有构件SMT...
  • wenlili
  • wenlili
  • 2012年02月18日 09:30
  • 2575

搭建邮件服务器之SMTP发送服务器(六)

创建postmaster帐户或别名 RFC 5321规定每个域必须具有邮政管理员邮箱并接受电子邮件。在接收来自您的电子邮件之前,存在检查此邮件的邮件系统。因此,请确保您在邮件服务器上创建一个po...
  • u011628250
  • u011628250
  • 2017年06月16日 08:53
  • 452

搭建邮件服务器之SMTP发送服务器(四)

发送方策略框架(SPF)已配置 目标邮件服务器可以执行的另一个操作来验证您的可信赖性是检查您的SPF记录。SPF记录是DNS中的TXT记录,用于定义哪些主机可以将源地址设置为特定域的电子邮件发送...
  • u011628250
  • u011628250
  • 2017年06月14日 08:44
  • 242

PHP用socket连接SMTP服务器发送邮件

PHP用socket连接SMTP服务器发送邮件 PHP用socket连接SMTP服务器发送邮件学习实验记录: 分析与SMTP会话的一般流程 1. HELO XXX \r\n //XX...
  • tty521
  • tty521
  • 2017年01月19日 11:34
  • 960

如何得到发送邮件服务器地址(SMTP地址)

很多网友程序中都要配置邮箱的,可以让系统自动发送信息。大家可以去http://qdcysm.cn.gongchang.com/去注册试试,发送邮件地址为 W E B@ A B O Y.C N 下面是...
  • GoodShot
  • GoodShot
  • 2013年05月25日 14:30
  • 195061

php中通过curl smtp发送邮件

先google了一下,发现很多问相关问题的但没有相关的解答,在phpclasses里也没有找到相关的类于是自己边看stmp的相关协议边开始尝试curl  SMTP协议  这个在网上可以找到多相关的...
  • hello_katty
  • hello_katty
  • 2015年05月11日 10:08
  • 1575

php发送邮件二种方法 php使用smtp发送邮件

原文:http://www.jbxue.com/php/25502.html 本文介绍了php发送邮件的两种方法,分别是使用PHP内置的mail()函数发送邮件,使用封装SMTP协议的邮件类发送...
  • lorielei
  • lorielei
  • 2015年08月11日 13:55
  • 1280

SMTP邮件发送不成功(所有文件留在Queue)

SMTP邮件发送不成功(所有文件留在Queue)
  • jason_dct
  • jason_dct
  • 2017年06月24日 18:01
  • 822

zabbix 配置外部邮件服务器发送邮件报警

zabbix 配置外部邮件服务器发送邮件报警
  • dai451954706
  • dai451954706
  • 2014年05月26日 10:43
  • 4394

PHP利用SMTP发送邮件,测试ok

当你还在纠结php内置的mail()函数不能发送邮件时,那么你现在很幸运,此时的这篇文章可以帮助到你! php利用smtp类来发邮件真是屡试不爽,我用过很久了,基本上没出过问题。本博客后台,当...
  • chuanyu
  • chuanyu
  • 2015年07月03日 12:06
  • 1714
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:不需要smtp服务器的邮件发送
举报原因:
原因补充:

(最多只允许输入30个字)