PDA

View Full Version : Sending email using Qt.



johnny_sparx
13th May 2006, 15:31
Is there a simple way to send email using Qt?
I see that it can be done by using ActiveQt to control Outlook. I am not interested in doing this. Is there another way?

jacek
13th May 2006, 18:02
You might try this: http://www.qtcentre.org/forum/showthread.php?t=183

nielsenj
16th May 2006, 17:24
Is there a simple way to send email using Qt?
I see that it can be done by using ActiveQt to control Outlook. I am not interested in doing this. Is there another way?

Depending on the version of QT, the 3.x series had a smtp mail example in the "networking" examples.

The modified structure for QT 4.x is below:

smtp.h


/************************************************** **************************
** $Id: qt/smtp.h 3.3.6 edited Aug 31 2005 $
**
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
**
** This file is part of an example program for Qt. This example
** program may be used, distributed and modified without limitation.
**
************************************************** ***************************/

#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(QTcpSocket::SocketState socketState);
void errorReceived(QTcpSocket::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


smtp.cpp

#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(SocketError)), this,
SLOT(errorReceived(SocketError)));
connect( socket, SIGNAL(stateChanged( SocketState)), this,
SLOT(stateChanged(SocketState)));
connect(socket, SIGNAL(disconnectedFromHost()), 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( "smtp.yourserver.com", 25);
if(socket->waitForConnected ( 30000 )) {qDebug("connected"); }

t = new QTextStream( socket );
}
Smtp::~Smtp()
{
delete t;
delete socket;
}
void Smtp::stateChanged(QTcpSocket::SocketState socketState)
{

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

void Smtp::errorReceived(QTcpSocket::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 = "";
}

To send a mail just use:

Smtp *newMail = new Smtp("from@address.com","to@address.com"," Your Subject","My body text");
delete newMail;

Please note: change the server address in "smtp.cpp" to your local server, most of the time localhost will work.. remote hosts should also work though.

As well, this may not work right off the bat, i speciallized it to work for my program.. i just hacked it back together for an example. The code is essentially correct, i just usually include the "To: BLAH\n", "From: BLAH\n" and "Subject: BLAH\n" within my message body.. so if there is something wrong it should be in that area.

Good Luck!

J

blue.death
31st May 2006, 16:30
Hi guys,

I am working on a SMTP client too and I do quite the same things as in the Qt example (btw. I didnt remember there was such an example ;) ).
The problem is my app won't connect if I don't call waitForConnected()!

But isnt this method useless if we wand non-blocking sockets?
Other code examples simply call connectToHost(...) after setting up the right connections.
If I don't call waitForConnected() the socket status remains on LookingUpHost (or whatever the exact name is)

Any clue???

jacek
31st May 2006, 16:32
If I don't call waitForConnected() the socket status remains on LookingUpHost (or whatever the exact name is)
Maybe you block the event loop? Do you check socket's status in some kind of a loop?

blue.death
31st May 2006, 16:54
Maybe you block the event loop? Do you check socket's status in some kind of a loop?

No, i connected the stateChanged() signal to a slot so I can keep track of the state changes.
If I don't call waitForConnected the state remains 1 and never changes.
If i call waitForConnected the connected() signal is emitted and the state changes to 2 and then 3 (connected).

jacek
31st May 2006, 17:04
No, i connected the stateChanged() signal to a slot so I can keep track of the state changes.
Do you have "QT += network" in your .pro file? Do you use threads? Maybe there's a loop that blocks the event loop in some other place?

blue.death
31st May 2006, 23:57
Do you have "QT += network" in your .pro file? Do you use threads? Maybe there's a loop that blocks the event loop in some other place?

.pro file is ok, otherwise it wouldnt build at all,
no threads, thats why i dont want blocking sockets,
and no event loop blocks ;)

I'm starting to think it's a problem with my Qt 4.1.3 on windoze.
I will see if i can post some code tomorrow.. i need some sleep now

patrik08
1st June 2006, 08:52
I rewrite the troll sample to make SMTP AUTH LOGIN work on qmail & postix tested...

Important is the mail date ..... the troll sample go unixtime zero 1970....



int dateswap(QString form, uint unixtime )
{
QDateTime fromunix;
fromunix.setTime_t(unixtime);
QString numeric = fromunix.toString((const QString)form);
bool ok;
return (int)numeric.toFloat(&ok);
}


QString TimeStampMail()
{
/* mail rtf Date format! http://www.faqs.org/rfcs/rfc788.html */
uint unixtime = (uint)time( NULL );
QDateTime fromunix;
fromunix.setTime_t(unixtime);
QStringList RTFdays = QStringList() << "giorno_NULL" << "Mon" << "Tue" << "Wed" << "Thu" << "Fri" << "Sat" << "Sun";
QStringList RTFmonth = QStringList() << "mese_NULL" << "Jan" << "Feb" << "Mar" << "Apr" << "May" << "Jun" << "Jul" << "Aug" << "Sep" << "Oct" << "Nov" << "Dec";
QDate timeroad(dateswap("yyyy",unixtime),dateswap("M",unixtime),dateswap("d",unixtime));
/*qDebug() << "### RTFdays " << RTFdays.at(timeroad.dayOfWeek());
qDebug() << "### RTFmonth " << RTFmonth.at(dateswap("M",unixtime));
qDebug() << "### yyyy " << dateswap("yyyy",unixtime);
qDebug() << "### M " << dateswap("M",unixtime);
qDebug() << "### d " << dateswap("d",unixtime);*/
QStringList rtfd_line;
rtfd_line.clear();
rtfd_line.append("Date: ");
rtfd_line.append(RTFdays.at(timeroad.dayOfWeek())) ;
rtfd_line.append(", ");
rtfd_line.append(QString::number(dateswap("d",unixtime)));
rtfd_line.append(" ");
rtfd_line.append(RTFmonth.at(dateswap("M",unixtime)));
rtfd_line.append(" ");
rtfd_line.append(QString::number(dateswap("yyyy",unixtime)));
rtfd_line.append(" ");
rtfd_line.append(fromunix.toString("hh:mm:ss"));
rtfd_line.append("");
/*qDebug() << "### mail rtf Date format " << rtfd_line.join("");*/
return QString(rtfd_line.join(""));
}

nielsenj
5th June 2006, 22:01
Hi guys,

I am working on a SMTP client too and I do quite the same things as in the Qt example (btw. I didnt remember there was such an example ;) ).
The problem is my app won't connect if I don't call waitForConnected()!

But isnt this method useless if we wand non-blocking sockets?
Other code examples simply call connectToHost(...) after setting up the right connections.
If I don't call waitForConnected() the socket status remains on LookingUpHost (or whatever the exact name is)

Any clue???


The example was only in the QT 3.x series under networking examples, i just altered it to work in QT 4.x.

My understanding of the "waitForConnected()" function is that it's simply a delay to allow a handshake to occur, it doesn't actually do anything unless you want to establish a timeout (lets say for a server that's offline) and take the bool return to do error correction.

Basically it is a delay before completing the socket.

I removed the "waitForConnected()" from my client and it established a connection immediately, but my mail server is also on the company lan and connects extremely quickly.

Using the "waitForConnected()" function should have no effect on how you connect unless you choose to implement error correction based on it's return.

If you don't want to use it then i suggest putting a delay in, something like 10-15 seconds, which is close to a worst case connection delay for most internet applications.

Of course if you use "waitForConnected(15000)" then it will automatically stop the delay after either 15 seconds (a timeout) or you establish a connection (if it's less than the passed 15 seconds), which would make sense to minimize the time your application is waiting.

J

pinktroll
26th July 2007, 08:59
Even this Post is old, it was very usefull for me. So a big thank you!!
But i have to notes for using MS Exchange Server (in my case Version 2000).
You have to change two things inside the code:

Don´t remove
if (smtpsocket->waitForConnected(Timeout)) or no mails will be send. Instead decrease the timeout, i.e. 500.
In function "PutSendLine()", in step "case 4"
replace the response "ok" with "Authentication successful" because this is the real responce and it wont work else.

Ryczypisk
4th November 2009, 12:47
Hello,
I'm newbie and I'd like to understand correctly this code.
Could you write what is the "output" is it sth. like stdout?:


void Smtp::connected()
{
output->append("connected");
qDebug() << "Connected ";
}

thanks

kremuwa
8th March 2010, 14:58
I used the structure from the post #9, taking into account post #11 (especially the second note). I am successfully connecting to the server and sending it those "lines" until it comes to send line number 7 (function PutSendLine(), case 7) - it's an actual message. After this line:

response = SendLineAndGrab(message+"\r\n.");
I'm receiving such a response from a server:

"550 5.5.2 Unknown command 'Date: Mon, 8 Mar 2010 15:54:26'
I have tried to remove the date (by commenting one of the first lines in smtp.cpp), but then I received similar response but this time it was aobut "User-Agent: Mozilla Thunderbird 1.0.6...".

Why is the server sending such responses? How to make it work?

obizy
12th March 2010, 12:09
in step 5
SendLineAndGrab("MAIL FROM: "+from);
someserver return:
501 Bad address syntax
so this line must chang to:
SendLineAndGrab("MAIL FROM:<"+from+">");

racinglocura07
15th June 2010, 16:20
How can we add to this code an option to send attached files?

squidge
15th June 2010, 18:33
7-bit encode the attachments using something like Base64 and then attach them to the body of the email as a MIME attachment making sure that the message and each attachment has a different id so that the receiving email client knows how to seperate the parts again.

estanisgeyer
15th June 2010, 21:38
See POCO Libraries, its very helpfull
http://pocoproject.org

racinglocura07
16th June 2010, 13:24
7-bit encode the attachments using something like Base64 and then attach them to the body of the email as a MIME attachment making sure that the message and each attachment has a different id so that the receiving email client knows how to seperate the parts again.

My mayor problem is that i receive an empty file if i do that, i must be doing something wrong

naghekyan
15th September 2010, 12:58
OK nielsenj demonstrated a nice axample how to send a mail via SMTP. But I can't find on the internet how to get the mail which is sent by the code of nielsenj.

baluk
18th September 2010, 16:23
Hi nielsenj,

I hope you are still active in this forum. I am new to Qt and I have the issue with smtp client. I have fallowed your code and am able to get the connected signal but immediately I am getting disconnected signal. Do you have any Idea why it is happening. I would be grateful to any help.

Thank you,
Baluk

squidge
18th September 2010, 16:59
Is the server working correctly? You can tell easily by using another email client and trying to send some mail.

baluk
19th September 2010, 13:41
Hi,

I am trying to send mail to gmail server. I don't need my own server.

Thank You,
Baluk

brushycreek
30th September 2010, 15:28
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;
...}

squidge
30th September 2010, 19:32
EDIT: Please don't post in multiple topics. It's considered rude. I posted a reply here only to notice that Wysota posted a reply in your other thread.

brushycreek
1st October 2010, 00:23
EDIT: Please don't post in multiple topics. It's considered rude. I posted a reply here only to notice that Wysota posted a reply in your other thread.
Yes, yes, yes. I have already had my hand slapped. Won't happen again. Thank you for responding.

Xila
7th September 2011, 14:22
Hi am new in qt..My problem is ..My application does connect to server but its not realy sending the emails that i want it to sent.Any help me

brushycreek
24th January 2012, 14:56
This thread has not had anyone post to it since September 2011. I am curious how many of the above posters were able to get their e-mail functionality working? After a push in the right direction from you guys, plus reading a book on SMTP and some additional web help on Enhanced SMTP, I was able to create a very robust and flexible e-mail client within my application. I have the option to require user authentication (Ehelo) and I can send attachments, which was the real reason that I even pursued having e-mail capabilities in the first place. The bottom line is that not only it is possible to send e-mails using SMTP/Enhanced SMTP, but it is possible to send attachments as well. The number of attachments and the file type does not matter. I hope you were all successful in your pursuit. Thanks for your input.

little_su
28th June 2012, 02:35
thank you very much

tetris11
4th August 2012, 19:09
Can someone post some working code please? It'd be much appreciated and save the rest of us a lot of time and effort.
Sure, we could dig at this for a few days and get it to eventually work -- but why climb a mountain when someone's already built an escalator?

Cheers in advance

monst
30th August 2012, 10:25
Also you can send e-mail by means of Qxt library http://libqxt.bitbucket.org. Namely, one can use

int send ( const QxtMailMessage & message )
of QxtSmtp class.

Coder5546
24th November 2012, 09:07
Depending on the version of QT, the 3.x series had a smtp mail example in the "networking" examples.

The modified structure for QT 4.x is below:

smtp.h


/************************************************** **************************
** $Id: qt/smtp.h 3.3.6 edited Aug 31 2005 $
**
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
**
** This file is part of an example program for Qt. This example
** program may be used, distributed and modified without limitation.
**
************************************************** ***************************/

#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(QTcpSocket::SocketState socketState);
void errorReceived(QTcpSocket::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


smtp.cpp

#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(SocketError)), this,
SLOT(errorReceived(SocketError)));
connect( socket, SIGNAL(stateChanged( SocketState)), this,
SLOT(stateChanged(SocketState)));
connect(socket, SIGNAL(disconnectedFromHost()), 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( "smtp.yourserver.com", 25);
if(socket->waitForConnected ( 30000 )) {qDebug("connected"); }

t = new QTextStream( socket );
}
Smtp::~Smtp()
{
delete t;
delete socket;
}
void Smtp::stateChanged(QTcpSocket::SocketState socketState)
{

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

void Smtp::errorReceived(QTcpSocket::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 = "";
}

To send a mail just use:

Smtp *newMail = new Smtp("from@address.com","to@address.com"," Your Subject","My body text");
delete newMail;

Please note: change the server address in "smtp.cpp" to your local server, most of the time localhost will work.. remote hosts should also work though.

As well, this may not work right off the bat, i speciallized it to work for my program.. i just hacked it back together for an example. The code is essentially correct, i just usually include the "To: BLAH\n", "From: BLAH\n" and "Subject: BLAH\n" within my message body.. so if there is something wrong it should be in that area.

Good Luck!

J

Hi, how I can add attachment to this code ?
Regards

IwantToLearen
12th February 2013, 17:51
Hello guys,
I am trying to send an email using the code in post#9, i did make the modifiction that were mentioned in post#11. I was trying to send a msg using gmail.
so what i did was :
Smtp = *newMail = new ("smtp.gmail.com","mygmail@gamil.com","mygmailPassward");
newMail->send("mygmail@gamil.com","mygmail@gamil.com","subject","body txt");

but i the connectoin does not want to establish
last msg i got is :

###Config server smtp connect to .............. "smtp.gmail.com"

can you please tell me what is wrong am i doing ??

thanks

d_stranz
12th February 2013, 19:58
so what i did was :

Smtp = *newMail = new ("smtp.gmail.com","mygmail@gamil.com","mygmailPass ward");

Really? How did you get your compiler to accept that?

IwantToLearen
12th February 2013, 20:20
Really? How did you get your compiler to accept that?

Man, take it easy it is just a typing mistake.

Smtp *newMail = new ("smtp.gmail.com","mygmail@gamil.com","mygmailPassward");

8Observer8
24th August 2013, 17:56
Hi,

I have questions about post #3 of this theme.

1. What is the server this:


socket->connectToHost( "smtp.yourserver.com", 25);

What have I write instead "smtp.yourserver.com"

2. What is the "output" variable? Is it for example?

Thank you!