我有一个应用程序,可以通过 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/