Я могу подключиться к серверу Yahoo SMTP, но не к серверу Gmail

У меня есть простой почтовый клиент SMTP. Я могу отправить электронное письмо, используя это приложение и мой почтовый аккаунт Yahoo. Но когда я собираюсь отправить электронное письмо, используя мою учетную запись Gmail, подключение к SMTP-серверу Google не удается!
Вот мой класс SMTP:

Smtp::Smtp( const QString &user, const QString &pass, const QString &host, int port, int timeout )
{
socket = new QSslSocket(this);

connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(socket, SIGNAL(connected()), this, SLOT(connected() ) );
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this,SLOT(errorReceived(QAbstractSocket::SocketError)));
connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(stateChanged(QAbstractSocket::SocketState)));
connect(socket, SIGNAL(disconnected()), this,SLOT(disconnected()));this->user = user;
this->pass = pass;

this->host = host;
this->port = port;
this->timeout = timeout;}

void Smtp::sendMail(const QString &from, const QString &to, const QString &subject, const QString &body)
{
// qDebug() << subject<<" ::: "<<body;
message = "To: " + to + "\n";
message.append(QString("From: " + from + "\n"));
message.append("Subject: " + subject + "\n");
message.append(body);

message.replace( QString::fromLatin1( "\n" ), QString::fromLatin1( "\r\n" ) );
message.replace( QString::fromLatin1( "\r\n.\r\n" ),
QString::fromLatin1( "\r\n..\r\n" ) );
//qDebug()<<message;
this->from = from;
rcpt = to;
state = Init;
socket->connectToHostEncrypted(host, port); //"smtp.gmail.com" and 465 for gmail TLS
if (!socket->waitForConnected(timeout)) {
qDebug() << socket->errorString();
}

t = new QTextStream( socket );
t->setCodec("UTF-8");
}

Smtp::~Smtp()
{
delete t;
delete socket;
}
void Smtp::stateChanged(QAbstractSocket::SocketState socketState)
{

qDebug() <<"stateChanged " << socketState;
}

void Smtp::errorReceived(QAbstractSocket::SocketError socketError)
{
qDebug() << "error " <<socketError;
}

void Smtp::disconnected()
{

qDebug() <<"disconneted";
qDebug() << "error "  << socket->errorString();
}

void Smtp::connected()
{
qDebug() << "Connected ";
}

void Smtp::readyRead()
{

qDebug() <<"readyRead";
// SMTP is line-oriented

QString responseLine;
do
{
responseLine = socket->readLine();
response += responseLine;
}
while ( socket->canReadLine() && responseLine[3] != ' ' );

responseLine.truncate( 3 );

qDebug() << "Server response code:" <<  responseLine;
qDebug() << "Server response: " << response;

if ( state == Init && responseLine == "220" )
{
// banner was okay, let's go on
*t << "EHLO localhost" <<"\r\n";
t->flush();

state = HandShake;
}
//No need, because I'm using socket->startClienEncryption() which makes the SSL handshake for you
/*else if (state == Tls && responseLine == "250")
{
// Trying AUTH
qDebug() << "STarting Tls";
*t << "STARTTLS" << "\r\n";
t->flush();
state = HandShake;
}*/
else if (state == HandShake && responseLine == "250")
{
socket->startClientEncryption();
if(!socket->waitForEncrypted(timeout))
{
qDebug() << socket->errorString();
state = Close;
}//Send EHLO once again but now encrypted

*t << "EHLO localhost" << "\r\n";
t->flush();
state = Auth;
}
else if (state == Auth && responseLine == "250")
{
// Trying AUTH
qDebug() << "Auth";
*t << "AUTH LOGIN" << "\r\n";
t->flush();
state = User;
}
else if (state == User && responseLine == "334")
{
//Trying User
qDebug() << "Username";
//GMAIL is using XOAUTH2 protocol, which basically means that password and username has to be sent in base64 coding
//https://developers.google.com/gmail/xoauth2_protocol
*t << QByteArray().append(user).toBase64()  << "\r\n";
t->flush();

state = Pass;
}
else if (state == Pass && responseLine == "334")
{
//Trying pass
qDebug() << "Pass";
*t << QByteArray().append(pass).toBase64() << "\r\n";
t->flush();

state = Mail;
}
else if ( state == Mail && responseLine == "235" )
{
// HELO response was okay (well, it has to be)

//Apperantly for Google it is mandatory to have MAIL FROM and RCPT email formated the following way -> <[email protected]>
qDebug() << "MAIL FROM:<" << from << ">";
*t << "MAIL FROM:<" << from << ">\r\n";
t->flush();
state = Rcpt;
}
else if ( state == Rcpt && responseLine == "250" )
{
//Apperantly for Google it is mandatory to have MAIL FROM and RCPT email formated the following way -> <[email protected]>
*t << "RCPT TO:<" << rcpt << ">\r\n"; //r
t->flush();
state = Data;
}
else if ( state == Data && responseLine == "250" )
{

*t << "DATA\r\n";
t->flush();
state = Body;
}
else if ( state == Body && responseLine == "354" )
{

*t << message << "\r\n.\r\n";
t->flush();
state = Quit;
}
else if ( state == Quit && responseLine == "250" )
{

*t << "QUIT\r\n";
t->flush();
// here, we just close.
state = Close;
emit status( tr( "Message sent" ) );
}
else if ( state == Close )
{
deleteLater();
return;
}
else
{
// something broke.
QMessageBox::warning( 0, tr( "Qt Simple SMTP client" ), tr( "Unexpected reply from SMTP server:\n\n" ) + response );
state = Close;
emit status( tr( "Failed to send message" ) );
}
response = "";
}

я использую smtp.mail.yahoo.com как Yahoo SMTP-сервер и smtp.gmail.com в качестве сервера SMTP Gmail. Я использую порт 465 для обоих.
Вот вывод отладки (хотя я думаю, что это бесполезно):

stateChanged  QAbstractSocket::HostLookupState
stateChanged  QAbstractSocket::ConnectingState
stateChanged  QAbstractSocket::UnconnectedState
error  QAbstractSocket::SocketTimeoutError
stateChanged  QAbstractSocket::UnconnectedState
"Socket operation timed out"

я использую Windows 7 64-битная . Qt 4.8.5 и visual studio 2008 !

4

Решение

Следующий образец отлично работает с GMAIL:

SmtpSsl::SmtpSsl(QObject *parent) :
QObject(parent) ,
smtp( new QSslSocket ) ,
istd( new QFile ) ,
ostd( new QFile )
{
qDebug() << "constructing";// QIODevice
QObject::connect( smtp , SIGNAL(aboutToClose()) , this , SLOT(sck_aboutToClose()) );
QObject::connect( smtp , SIGNAL(bytesWritten(qint64)) , this , SLOT    (sck_bytesWritten(qint64)) );
QObject::connect( smtp , SIGNAL(readChannelFinished()) , this , SLOT(sck_readChannelFinished()) );
QObject::connect( smtp , SIGNAL(readyRead()) , this , SLOT(sck_readyRead()) );// QAbstractSocket
QObject::connect( smtp , SIGNAL(connected()) , this , SLOT(sck_connected()) );
QObject::connect( smtp , SIGNAL(disconnected()) , this , SLOT(sck_disconnected()) );
QObject::connect( smtp , SIGNAL(error(QAbstractSocket::SocketError)) , this , SLOT(sck_error(QAbstractSocket::SocketError)) );
QObject::connect( smtp , SIGNAL(hostFound()) , this , SLOT(sck_hostfound()) );
QObject::connect( smtp , SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)) , this , SLOT(sck_proxyAuthRequired()) );
QObject::connect( smtp , SIGNAL(stateChanged(QAbstractSocket::SocketState)) , this , SLOT(sck_stateChanged(QAbstractSocket::SocketState)) );// QSslSocket
QObject::connect( smtp , SIGNAL(encrypted()) , this , SLOT(sck_encrypted()) );
QObject::connect( smtp , SIGNAL(encryptedBytesWritten(qint64)) , this , SLOT(sck_encryptedBytesWritten(qint64)) );
QObject::connect( smtp , SIGNAL(modeChanged(QSslSocket::SslMode)) , this , SLOT(sck_modeChanged(QSslSocket::SslMode)) );
QObject::connect( smtp , SIGNAL(sslErrors(QList<QSslError>)) , this , SLOT(sck_sslErrors(QList<QSslError>)) );
QObject::connect( smtp , SIGNAL(peerVerifyError(QSslError)) , this , SLOT(sck_peerVerifyError(QSslError)) );// public part
QObject::connect( smtp , SIGNAL(encrypted()) , this , SLOT(start_session()) );
QObject::connect( smtp , SIGNAL(disconnected()) , this , SLOT(deleteLater()) );

smtp->setPeerVerifyMode( QSslSocket::VerifyPeer );
smtp->connectToHostEncrypted( "smtp.gmail.com" , 465 );
istd->open( stdin  , QIODevice::ReadOnly );
ostd->open( stdout , QIODevice::WriteOnly );

qDebug() << "constructed";
}

SmtpSsl::~SmtpSsl()
{
qDebug() << "destroying";
delete smtp;
qDebug() << "destroyed";
}

void
SmtpSsl::start_session()
{
QObject::connect( smtp , SIGNAL(readyRead()) , this , SLOT(receive()) );
}

void    SmtpSsl::receive()
{
ostd->write( smtp->readAll() );
ostd->flush();

smtp->write( istd->readLine() );
}

Что касается вашего образца. Я могу догадаться, что у вас есть один из следующих случаев:

  1. у вас проблемы с подключением на уровне сети. Вы можете подключиться
    smtp.gmail.com порт 465 без SSL?
  2. Я полагаю, у вас есть это дело. Вы перехватываете готовый сигнал
    и, вероятно, (этот код не был показан здесь) читать полученные данные
    до Вы вошли в зашифрованное состояние (т.е. данные рукопожатия SSL). Из-за того, что вы прочитали данные рукопожатия, QSslSocket будет ждать до
    Это может прочитать захваченные данные рукопожатия, что приведет к тайм-ауту.

Надеюсь, это поможет.

3

Другие решения

вы должны использовать порт 587 для gmail включите ssl,tls а также auth, Вот мое рабочее решение, написанное на Java, этот код не использует Qt рамки, но он может показать вам, как настроить smtp сервер для отправки электронной почты через Gmail правильно.

public void sendMail2(){
Email email = new SimpleEmail();
try {
DateFormat dateFormat = new SimpleDateFormat(
"yyyy/MM/dd HH:mm:ss");
Calendar c = new GregorianCalendar();
String authuser="[email protected]";String authpwd="passtoyouraccount";
email.setSmtpPort(587);
email.setAuthenticator(new DefaultAuthenticator(authuser,authpwd));
email.setDebug(true);
email.setHostName("smtp.gmail.com");
email.getMailSession().getProperties().put("mail.smtps.auth","true");
email.getMailSession().getProperties().put("mail.debug", "true");
email.getMailSession().getProperties().put("mail.smtps.port","587");
email.getMailSession().getProperties().put(
"mail.smtps.socketFactory.port", "587");
email.getMailSession().getProperties().put(
"mail.smtps.socketFactory.class",
"javax.net.ssl.SSLSocketFactory");
email.getMailSession().getProperties().put(
"mail.smtps.socketFactory.fallback", "false");
email.getMailSession().getProperties().put(
"mail.smtp.starttls.enable", "true");
email.setFrom("[email protected]", "my_site");
email.setSubject("new message");
Date date = new Date();
email.setMsg("from: "+userMail+"\ndate:"+dateFormat.format(date)+"\n\n"+mailContent);
email.addTo("[email protected]","ToName");
email.send();
} catch (EmailException e) {
e.printStackTrace();
}
4

По вопросам рекламы [email protected]