PDA

View Full Version : send mail from qt app problem



cutie.monkey
27th January 2009, 06:13
hi all...

i'm currently developing an application that will send an email. ive'd search the forum for the similar topics, and found out some.

i used the smtp code:

smtp.cpp


#include "smtp.h"
#include <QAbstractSocket>

Smtp::Smtp( const QString &strmailserver, const int &port, const QString &from, const QString &to, const QString &subject, const QString &body )
{

socket = new QTcpSocket( 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()));;

message = "To: " + to + "\n";
message.append("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" ) );
this->from = from;
rcpt = to;
state = Init;



socket->connectToHost( strmailserver , port);
if(socket->waitForConnected ( 10000 )){
qDebug("connected");
}

t = new QTextStream( 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()
{
//output->append("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 );


if ( state == Init && responseLine[0] == '2' )
{
// banner was okay, let's go on

*t << "HELO there\r\n";
t->flush();

state = Mail;
}
else if ( state == Mail && responseLine[0] == '2' )
{
// HELO response was okay (well, it has to be)

*t << "MAIL FROM: " << from << "\r\n";
t->flush();
state = Rcpt;
}
else if ( state == Rcpt && responseLine[0] == '2' )
{

*t << "RCPT TO: " << rcpt << "\r\n"; //r
t->flush();
state = Data;
}
else if ( state == Data && responseLine[0] == '2' )
{

*t << "DATA\r\n";
t->flush();
state = Body;
}
else if ( state == Body && responseLine[0] == '3' )
{

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

*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 Mail Example" ), tr( "Unexpected reply from SMTP server:\n\n" ) + response );
state = Close;
}
response = "";
}
Smtp::~Smtp()
{
delete t;
delete socket;
}



smtp.h


#ifndef SMTP_H
#define SMTP_H

#include <QTcpSocket>
#include <QString>
#include <QTextStream>
#include <QDebug>
#include <QMessageBox>

class Smtp : public QObject
{
Q_OBJECT


public:
Smtp( const QString &strmailserver, const int &port, const QString &from, const QString &to,
const QString &subject, const QString &body );
~Smtp();

signals:
void status( const QString &);

private slots:
void stateChanged(QAbstractSocket::SocketState socketState);
void errorReceived(QAbstractSocket::SocketError socketError);
void disconnected();
void connected();
void readyRead();

private:
QString message;
QTextStream *t;
QTcpSocket *socket;
QString from;
QString rcpt;
QString response;
enum states{Rcpt,Mail,Data,Init,Body,Quit,Close};
int state;

};
#endif


i call the class with this parameters:



Smtp *sendMail = new Smtp( "my-mail-server", 25, "myemail@yahoo.com","receiveremail@yahoo.com", "Subject", "This is the message.");
delete sendMail;


during runtime the debug output is:



stateChanged QAbstractSocket::HostLookupState
stateChanged QAbstractSocket::ConnectingState
stateChanged QAbstractSocket::ConnectedState
Connected
connected
stateChanged QAbstractSocket::ClosingState
stateChanged QAbstractSocket::UnconnectedState
disconneted


now, i check my email and i havent receive any mail. is there anyone here who knows how to fix this? thnks a lot..

caduel
27th January 2009, 08:13
Well, Smtp is working with signals/slots and is asynchronous. (It needs an QEventLoop running.)

You delete the object right after creating it. You connect in the constructor (wait for some reasing synchronously for the connection to be established). Then you exit the constructor and the caller immediately deletes to smtp object. This a) causes a disconnect (good thing) and b) obviously prevents any data from being read in your read-Slot etc.

Just do not delete the object (at least not until you're done).

cutie.monkey
27th January 2009, 08:50
thnks.. its finally working.. i checked my code and found out that when i call the smtp class, i used delete sendMail which is wrong..

cutie.monkey
4th March 2009, 02:05
hi! all, another question..

using the smtp class, im trying to send mail to multiple recipients, that is, each email add is separated by a semi colon ';', but during runtime an error occured,


Unexpected reply from SMTP server: 500 Syntax error, command unrecognized


is there anyone here knows how to solve this error or knows another way to send email to multiple recipients, also with cc(carbon copy)?

thank you very much!

estanisgeyer
6th March 2009, 18:38
It's possible to attach file?

talk2amulya
6th March 2009, 19:17
its clearly a command error..which means the data u r sending is wrong or formatted wrongly..hv a look at example of expanding a mailing list in:

http://www.ietf.org/rfc/rfc0821.txt

this will give a much better insight into everything u are doing and u'll be able to debug well.

baluk
21st September 2010, 07:47
Hi,

I too am using the same code for mailing. But I am still not able to send any mail. When I run the app, it is stayed on Connected state not going any further. I would be grateful to any help.


#include "smtp.h"

Smtp::Smtp( const QString &from, const QString &to, const QString &subject, const QString &body )
{
socket = new QTcpSocket( 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()));;

message = "To: " + to + "\n";
message.append("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" ) );
this->from = from;
rcpt = to;
state = Init;
this->Maddress = to.mid( to.indexOf('@',1)+1);
QString s= "smtp.";
s.append(this->Maddress);
socket->connectToHost( s , 465);

if(socket->waitForConnected ( 40000 )) {qDebug("connected"); }

t = new QTextStream( socket );
}
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()
{
//output->append("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 );


if ( state == Init && responseLine[0] == '2' )
{
// banner was okay, let's go on

*t << "HELO there\r\n";
t->flush();

state = Mail;
}
else if ( state == Mail && responseLine[0] == '2' )
{
// HELO response was okay (well, it has to be)

*t << "MAIL FROM: " << from << "\r\n";
t->flush();
state = Rcpt;
}
else if ( state == Rcpt && responseLine[0] == '2' )
{

*t << "RCPT TO: " << rcpt << "\r\n"; //r
t->flush();
state = Data;
}
else if ( state == Data && responseLine[0] == '2' )
{

*t << "DATA\r\n";
t->flush();
state = Body;
}
else if ( state == Body && responseLine[0] == '3' )
{

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

*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 Mail Example" ), tr( "Unexpected reply from SMTP server:\n\n" ) + response );
state = Close;
}
response = "";
}


#ifndef SMTP_H
#define SMTP_H

#include <QTcpSocket>
#include <QString>
#include <QTextStream>
#include <QDebug>
#include <QMessageBox>

class Smtp : public QObject
{
Q_OBJECT


public:
Smtp( const QString &from, const QString &to,
const QString &subject, const QString &body );
~Smtp();

signals:
void status( const QString &);

private slots:
void stateChanged(QAbstractSocket::SocketState socketState);
void errorReceived(QAbstractSocket::SocketError socketError);
void disconnected();
void connected();
void readyRead();

private:
QString message;
QTextStream *t;
QTcpSocket *socket;
QString from;
QString rcpt;
QString Maddress;
QString response;
enum states{Rcpt,Mail,Data,Init,Body,Quit,Close};
int state;

};
#endif


stateChanged QAbstractSocket::HostLookupState
stateChanged QAbstractSocket::ConnectingState
stateChanged QAbstractSocket::ConnectedState
Connected
connected

I am trying to send mail to xxx@gmail.com and from xx@hotmail.com

Thank you,
Baluk

squidge
21st September 2010, 09:00
Your code is flawed. You can not assume that every mail server starts with 'smtp' and ends with a part of the users mail address.

You will have to do a proper mail exchanger lookup and connect to that host instead. This doesn't cure all your problems however, as lots of servers block connections from ADSL/Cable IP addresses. To only way around this is to run your own server and connect to that one.

wysota
21st September 2010, 09:58
Furthermore many servers reject email the first time it is sent and you have to resend it after some grace time. This is called graylisting. Some servers will just reject your mail because it is being sent from a wrong ip, etc.

If you want to send mails directly from your application, you should be connecting to a server you know will accept your mail and then let it handle the mail routing. Then you don't have to do any server lookups and such.

brushycreek
30th September 2010, 16:27
Hello all! First I want to thank all of you. This information has been very helpful. With some minor modifications, I am now able to send an email via SMTP. The code that I am using was pasted from this forum and tweaked to get it to work with Qt4.6.2.

I am having one issue though - my body text never gets transferred! What is happening? I get a subject line, but no body text. My ultimate goal is to attach a file, but I am a bit worried about accomplishing that if I cannot even get my body text to show up!

It is this part of the code that I really do not understand. 1) Does it have to be done in this manner? 2) What is the purpose of the replaces? 3) How is SMTP getting my Subject Text, but not my Body Text? Any help is appreciated. (P.S. I am going to post this on another thread in order to make sure it gets seen).



Smtp::Smtp( const QString &from, const QString &to, const QString &subject, const QString &body ) {
...
sMessage = "To: " + to + "\n";
sMessage.append("From: " + from + "\n");
sMessage.append("Subject: " + subject + "\n");
sMessage.append(body);
sMessage.replace( QString::fromLatin1( "\n" ), QString::fromLatin1( "\r\n" ) );
sMessage.replace( QString::fromLatin1( "\r\n.\r\n" ), QString::fromLatin1( "\r\n..\r\n" ) );
sFrom = from;
sTo = to;
...}

wysota
30th September 2010, 17:49
There needs to be an empty line between the last header ("Subject" in your case) and first line of the body of the message.


(P.S. I am going to post this on another thread in order to make sure it gets seen).
Please don't do that. We can see your message very well.

brushycreek
30th September 2010, 18:09
There needs to be an empty line between the last header ("Subject" in your case) and first line of the body of the message.

Excellent! Here are the results. I tried:


sMessage.append("Subject: " + subject + "\n");
sMessage.append("\r\n" + body);


which yielded body text and I tried:



sMessage.append("Subject: " + subject + "\r\n");
sMessage.append(body);


which also yielded body text. It seems that the "\r" is missing from all of the code snippets in the thread. Thank you! Btw, I am also getting:

X-UIDL: 576795945
X-IMail-ThreadID: b5a1038d0000ddec

appended to the end of my body text. What is that?


Please don't do that. We can see your message very well.

Yes sir. :o

squidge
30th September 2010, 20:31
The \r are not missing at all, they are implemented near the end:

sMessage.replace( QString::fromLatin1( "\n" ), QString::fromLatin1( "\r\n" ) );