sockets - SMTP 邮件服务器 (sendgrid) 提交时出错

标签 sockets email smtp base64 sendgrid

我有一个应用程序,可以通过 SMTP 服务器 (sendgrid) 发送带有图像附件的电子邮件。

当应用程序启动时,它会初始化一个 Socket 连接并验证用户(应用程序)。我看到从 Sendgrid 返回的以下消息

SG ESMTP service ready at<foo..sendgrid.net

并且我还得到了成功的身份验证返回。

但是,在发送电子邮件时,我收到以下 3 个错误:

error 1 550  Unauthenticated senders not allowed
error 2 503 Must have sender before recipient
error 3 503 Must have valid receiver and originator

因此,这表明我必须更改 SMTP 模块中发件人和收件人的顺序。在内部,我正在获取传入的 ByteArray 并转换为 base64 字符串,以便发送带有附加文件的电子邮件。

那么我如何更改以下代码摘录?

        writeUTFBytes ("MAIL FROM: <"+pFrom+">\r\n");
        writeUTFBytes ("RCPT TO: <"+pDest+">\r\n");
        writeUTFBytes ("DATA\r\n");
        writeUTFBytes ("From: "+pFrom+"\r\n");
        writeUTFBytes ("To: "+pDest+"\r\n");

这是我正在使用的整个类。我在类初始化后仅调用一次authenticate,然后在发送带有图像附件的电子邮件时调用sendAttachedMail。当使用没有身份验证的本地 SMTP 服务器进行测试时,一切正常(发送电子邮件和图像附件)

package org.bytearray.smtp.mailer
{
    import flash.events.ProgressEvent;
    import flash.net.Socket;
    import flash.utils.ByteArray;
    import flash.utils.getTimer;

    import org.bytearray.smtp.crypto.MD5;
    import org.bytearray.smtp.encoding.Base64;
    import org.bytearray.smtp.events.SMTPEvent;
    import org.bytearray.smtp.infos.SMTPInfos;

    public class SMTPMailer extends Socket 
    {
        private var sHost:String;
        private var buffer:Array = new Array();

        // regexp pattern
        private var reg:RegExp = /^\d{3}/img;

        // PNG, JPEG header values
        private static const PNG:Number = 0x89504E47;
        private static const JPEG:Number = 0xFFD8;

        // common SMTP server response codes
        // other codes could be added to add fonctionalities and more events
        private static const ACTION_OK:Number = 0xFA;
        private static const AUTHENTICATED:Number = 0xEB;
        private static const DISCONNECTED:Number = 0xDD;
        private static const READY:Number = 0xDC;
        private static const DATA:Number = 0x162;
        private static const BAD_SEQUENCE:Number = 0x1F7;

        public function SMTPMailer ( pHost:String, pPort:int) 
        {
            super ( pHost, pPort );         
            sHost = pHost;
            addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler,false,0,true);
        }

        public function reset():void{
            removeEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
        }

        /*
        * This method lets you authenticate, just pass a login and password
        */
        public function authenticate ( pLogin:String, pPass:String ):void
        {
            writeUTFBytes ("EHLO "+sHost+"\r\n");
            writeUTFBytes ("AUTH LOGIN\r\n");
            writeUTFBytes (Base64.encode64String (pLogin)+"\r\n");
            writeUTFBytes (Base64.encode64String (pPass)+"\r\n");
            flush();
        }

        /*
        * This method is used to send emails with attached files and HTML 
        * takes an incoming Bytearray and convert it to base64 string
        * for instance pass a JPEG ByteArray stream to get a picture attached in the mail ;)
        */
        public function sendAttachedMail ( pFrom:String, pDest:String, pSubject:String, pMess:String, pByteArray:ByteArray, pFileName:String ) :void
        {
            try {

                writeUTFBytes ("HELO "+sHost+"\r\n");
                writeUTFBytes ("MAIL FROM: <"+pFrom+">\r\n");
                writeUTFBytes ("RCPT TO: <"+pDest+">\r\n");
                writeUTFBytes ("DATA\r\n");
                writeUTFBytes ("From: "+pFrom+"\r\n");
                writeUTFBytes ("To: "+pDest+"\r\n");
                writeUTFBytes ("Date : "+new Date().toString()+"\r\n");
                writeUTFBytes ("Subject: "+pSubject+"\r\n");
                writeUTFBytes ("Mime-Version: 1.0\r\n");

                var md5Boundary:String = MD5.hash ( String ( getTimer() ) );

                writeUTFBytes ("Content-Type: multipart/mixed; boundary=------------"+md5Boundary+"\r\n");
                writeUTFBytes("\r\n");
                writeUTFBytes ("This is a multi-part message in MIME format.\r\n");
                writeUTFBytes ("--------------"+md5Boundary+"\r\n");
                writeUTFBytes ("Content-Type: text/html; charset=UTF-8; format=flowed\r\n");
                writeUTFBytes("\r\n");
                writeUTFBytes (pMess+"\r\n");
                writeUTFBytes ("--------------"+md5Boundary+"\r\n");
                writeUTFBytes ( readHeader (pByteArray, pFileName) );
                writeUTFBytes ("Content-Transfer-Encoding: base64\r\n");
                writeUTFBytes ("\r\n");

                var base64String:String = Base64.encode64 ( pByteArray, true );

                writeUTFBytes ( base64String+"\r\n");
                writeUTFBytes ("--------------"+md5Boundary+"-\r\n");
                writeUTFBytes (".\r\n");
                flush();

            } catch ( pError:Error )
            {
                trace("Error : Socket error, please check the sendAttachedMail() method parameters");
                trace("Arguments : " + arguments );     
            }
        }

        /*
        * This method is used to send HTML emails
        * just pass the HTML string to pMess
        */
        public function sendHTMLMail ( pFrom:String, pDest:String, pSubject:String, pMess:String ):void
        {
            try 
            {           
                writeUTFBytes ("HELO "+sHost+"\r\n");
                writeUTFBytes ("MAIL FROM: <"+pFrom+">\r\n");
                writeUTFBytes ("RCPT TO: <"+pDest+">\r\n");
                writeUTFBytes ("DATA\r\n");
                writeUTFBytes ("From: "+pFrom+"\r\n");
                writeUTFBytes ("To: "+pDest+"\r\n");
                writeUTFBytes ("Subject: "+pSubject+"\r\n");
                writeUTFBytes ("Mime-Version: 1.0\r\n");
                writeUTFBytes ("Content-Type: text/html; charset=UTF-8; format=flowed\r\n");
                writeUTFBytes("\r\n");
                writeUTFBytes (pMess+"\r\n");
                writeUTFBytes (".\r\n");
                flush();

            } catch ( pError:Error )
            {   
                trace("Error : Socket error, please check the sendHTMLMail() method parameters");
                trace("Arguments : " + arguments ); 
            }
        }

        /*
        * This method automatically detects the header of the binary stream and returns appropriate headers (jpg, png)
        * classic application/octet-stream content type is added for different kind of files
        */
        private function readHeader ( pByteArray:ByteArray, pFileName:String ):String 
        {
            pByteArray.position = 0;

            var sOutput:String = null;

            if ( pByteArray.readUnsignedInt () == SMTPMailer.PNG ) 
            {
                sOutput = "Content-Type: image/png; name="+pFileName+"\r\n";
                sOutput += "Content-Disposition: attachment filename="+pFileName+"\r\n";
                return sOutput; 
            }

            pByteArray.position = 0;

            if ( pByteArray.readUnsignedShort() == SMTPMailer.JPEG ) 
            {
                sOutput = "Content-Type: image/jpeg; name="+pFileName+"\r\n";
                sOutput += "Content-Disposition: attachment filename="+pFileName+"\r\n";
                return sOutput; 
            }

            sOutput = "Content-Type: application/octet-stream; name="+pFileName+"\r\n";
            sOutput += "Content-Disposition: attachment filename="+pFileName+"\r\n";

            return sOutput;
        }

        // check SMTP response and dispatch proper events
        // Keep in mind SMTP servers can have different result messages the detection can be modified to match some specific SMTP servers
        private function socketDataHandler ( pEvt:ProgressEvent ):void
        {
            var response:String = pEvt.target.readUTFBytes ( pEvt.target.bytesAvailable );
            buffer.length = 0;
            var result:Array = reg.exec(response);

            while (result != null)
            {   
                buffer.push (result[0]);
                result = reg.exec(response);
            }

            var smtpReturn:Number = buffer[buffer.length-1];
            var smtpInfos:SMTPInfos = new SMTPInfos ( smtpReturn, response );

            if ( smtpReturn == SMTPMailer.READY ) 
                dispatchEvent ( new SMTPEvent ( SMTPEvent.CONNECTED, smtpInfos ) );

            else if ( smtpReturn == SMTPMailer.ACTION_OK && (response.toLowerCase().indexOf ("queued") != -1 || response.toLowerCase().indexOf ("accepted") != -1 ||
                    response.toLowerCase().indexOf ("qp") != -1) ) dispatchEvent ( new SMTPEvent ( SMTPEvent.MAIL_SENT, smtpInfos ) );
            else if ( smtpReturn == SMTPMailer.AUTHENTICATED ) 
                dispatchEvent ( new SMTPEvent ( SMTPEvent.AUTHENTICATED, smtpInfos ) );
            else if ( smtpReturn == SMTPMailer.DISCONNECTED ) 
                dispatchEvent ( new SMTPEvent ( SMTPEvent.DISCONNECTED, smtpInfos ) );
            else if ( smtpReturn == SMTPMailer.BAD_SEQUENCE ) 
                dispatchEvent ( new SMTPEvent ( SMTPEvent.BAD_SEQUENCE, smtpInfos ) );
            else if ( smtpReturn != SMTPMailer.DATA ) 
                dispatchEvent ( new SMTPEvent ( SMTPEvent.MAIL_ERROR, smtpInfos ) );    
        }
    }
}

最佳答案

So this suggests to me that I must change the order of sender and recipient in my SMTP module.

您的命令顺序是正确的。相反,您应该查看第一条错误消息以了解问题的真正原因:

 error 1 550  Unauthenticated senders not allowed

这告诉您 server requires authentication来自发件人,即使用带有用户凭据的 SMTP AUTH 命令。未经身份验证的发件人尝试发送邮件将被拒绝。因此,如果 MAIL FROM 失败,则 RCPT TO 也会失败。如果RCPT TO失败,则DATA失败。等等。

使用 SMTP EHLO 命令发现服务器支持的 AUTH 方案(和其他功能),然后发送适当的 AUTH发送MAIL FROM之前的命令。

关于sockets - SMTP 邮件服务器 (sendgrid) 提交时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39901300/

相关文章:

ios - 使用套接字的 iOS 应用程序之间是否可以进行进程间通信?

linux - 如何通过套接字将 `eof` 信号发送到在远程 shell 中运行的命令?

language-agnostic - 如何开发和测试发送电子邮件的应用程序(无需在某人的邮箱中填充测试数据)?

go - 使用 Golang 连接到 Exchange

c# - 不完整的消息(C# TCP/IP 客户端)

php - 如何从 PHP 中的字符串中删除电子邮件地址和链接?

从 VPS 发送的电子邮件进入垃圾邮件文件夹或被阻止

Azure 网站 Elmah SMTP 邮件在部署时无法工作

c# - 使用 Mailkit : "The SMTP server has unexpectedly disconnected."

c - 使用代码块进行套接字编程