## Simple TLS/SSL SMTP client for Qt5

For one of my projects I wanted to develop a crash reporting dialog where user can enter the steps he did to crash the application and then by pressing send button the app automatically will send me user report and the log to my e-mail address. Unfortunatelly Qt doesn't have a Smtp library, and I don't want anything heavy just to send a simple string of characters through gmail smtp server.

### Update

Both implementations are now available on github

There are some examples and codes on github like:
https://github.com/bluetiger9/SmtpClient-for-Qt

The above one actually looks like very decent peace of code, however again, it is a little bit too heavy for my taste and it didn't compile on Qt5 immidiatly (even the example) and I didn't want to go through to try and fix it.

So I found an example code for SMTP from Qt3. Which was almost exactly what I was looking for, it was simple for sure. However, it lacked two major features, it didn't support TLS/SSL communication and authentification I need it to use gmail as my smtp server. Then I thought how hard would it be to improve that code?

## SMTP protocol for sending email

First of all every communication with the server will result a response from server. It is important to extract first 3 characters from the message which are response codes. Those codes obviously will be used for error checking whether communication is going smoothly.

#### Basic algorithm for sending email through smtp:

1. Connecting to the server and waiting for greeting message
2. If response code = 220 then send a greeting back to server "EHLO yourdomain.com\r\n"
3. If response code = 250 then identify from whom the mail is coming from by sending "MAIL FROM:<youremail@mail.com>\r\n"
4. If response code = 250 then send whom the email is addressed to "RCPT TO:<send_to@mail.com>\r\n"
5. If response code = 250 then now it is time to inititate sending the contents of the email by sending "DATA\r\n"
6. If response code = 354 then send your contents for example "This is an email\r\n"
7. If response code = 250 then your email has been sent and now you can close the connection by sending "QUIT\r\n"

#### Basically the above algorithm was used in the example code I found from Qt3. As you can see the above algorithm lacks authentification and SSL/TLS handshake. To do add those things to the code it turned out to be actually simpler than I first anticipated.  Basic algorithm for TLS/SSL smtp email sending:

1. Connecting to the server and waiting for greeting message
2. If response code = 220 then send a greeting back to server "EHLO yourdomain.com\r\n"
3. If response code = 250 then initiate TLS communication by making a SSL/TLS handshake, for this I use the methods provided in QSslSocket class, more precisely QSslSocket::startClientEncryption(). (make communictaion encrypted)
4. If response code = 250 then you have successfully initiated a encrypted communication and now we can start authentification by sending "AUTH LOGIN\r\n"
5. If response code = 334 then the server is waiting for username, since my aim was to use GMAIL as smtp server their API states that the username and password must be sent in base64 coding, it would look something like this "bXlfdXNlcm5hbWU=\r\n"  (my_username)
6. If response code = 334 then send the server password, and again in base64 coding "bXlfcGFzc3dvcmQ=\r\n" (my_password)
7. If response code = 235 then you have successfully logged in and now you can identify from whom the mail is coming from by sending "MAIL FROM:<youremail@mail.com>\r\n"
8. If response code = 250 then send whom the email is addressed to "RCPT TO:<send_to@mail.com>\r\n"
9. If response code = 250 then now it is time to inititate sending the contents of the email by sending "DATA\r\n"
10. If response code = 354 then send your contents for example "This is an email\r\n"
11. If response code = 250 then your email has been sent and now you can close the connection by sending "QUIT\r\n"

That's it, by following the above pseudo code, you should be able to write a simple TLS/SSL SMTP client for sending email using gmail as smtp server. You can use the above approach to send email through telnet aswell.

Important: Every command to server has to be finished with carriege return and new line symbol in other words you have to finish the line with "\r\n"

So by following the steps I wrote above, I slightly rewrote the example code which you can see below. However I would advise just trying to write the code yourself, belive it's not that hard, if you follow the steps.

First of all, for the code to run you will need Qt with ssl support compiled within and OpenSSL library . If you have ssl compiled in the Qt library you don't need to add anything to the pro file, except QT+= network.

Smtp.h

/*

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/

#ifndef SMTP_H
#define SMTP_H

#include <QtNetwork/QAbstractSocket>
#include <QtNetwork/QSslSocket>
#include < QString >
#include < QTextStream >
#include < QDebug >
#include <QtWidgets/QMessageBox>
#include < QByteArray >

class Smtp : public QObject
{
Q_OBJECT

public:
Smtp( const QString &user, const QString &pass,
const QString &host, int port = 465, int timeout = 30000 );
~Smtp();

void sendMail( const QString &from, const QString &to,
const QString &subject, const QString &body );

signals:
void status( const QString &);

private slots:
void stateChanged(QAbstractSocket::SocketState socketState);
void disconnected();
void connected();

private:
int timeout;
QString message;
QTextStream *t;
QSslSocket *socket;
QString from;
QString rcpt;
QString response;
QString user;
QString pass;
QString host;
int port;
enum states{Tls, HandShake ,Auth,User,Pass,Rcpt,Mail,Data,Init,Body,Quit,Close};
int state;

};
#endif

Smtp.cpp

/*

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/

#include "smtp.h"

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

connect(socket, SIGNAL(connected()), this, SLOT(connected() ) );
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)
{
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->connectToHostEncrypted(host, port); //"smtp.gmail.com" and 465 for gmail TLS
if (!socket->waitForConnected(timeout)) {
qDebug() << socket->errorString();
}

t = new QTextStream( socket );

}

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

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

{
qDebug() << "error " <<socketError;
}

void Smtp::disconnected()
{

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

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

{

// SMTP is line-oriented

QString responseLine;
do
{
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
//GMAIL is using XOAUTH2 protocol, which basically means that password and username has to be sent in base64 coding
*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@gmail.com>
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@gmail.com>
*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 = "";
}

Example usage:

smtp = new Smtp("your_username@gmail.com", "your_password", "smtp.gmail.com");
connect(smtp, SIGNAL(status(QString)), this, SLOT(mailSent(QString)));

smtp->sendMail("sent_from@gmail.com", "send_it_to@gmail.com" , "This is a subject","This is a body");


That's all you have to do, to send a simple text based email through Qt5 and most likely Qt4 as well. ENJOY!

The result:

To run the exectutable you have to install Qt5, Microsoft Visual C++ redistributables and OpenSSL on your computer.
To compile you just need OpenSSL and Qt5!

If you want file attachemnt support as well refer to my other article, which improves this piece of code for attachment support.

References:

Network Sorcery Inc.. (Not Available). SMTP, Simple Mail Transfer Protocol. Available: http://www.networksorcery.com/enp/protocol/smtp.htm. Last accessed 9th Jul 2013.

Microsoft. (2003). What is TLS/SSL?. Available: http://technet.microsoft.com/en-us/library/cc784450%28v=ws.10%29.aspx. Last accessed 9th Jul 2013.

### Related Articles

• #### Implementing pulse oximeter using MAX30100

Mar 8, 2017 | by Raivis Strogonovs
• #### nRF51 Makefile with Qt Creator

Jun 4, 2016 | by Raivis Strogonovs
• #### USART, FreeRTOS and C++ on nRF51

Dec 14, 2015 | by Raivis Strogonovs
• #### Starting with nRF51 BLE and Qt Creator

Dec 12, 2015 | by Raivis Strogonovs
• #### Touch gesture recognition using body capacitance

Nov 29, 2014 | by Raivis Strogonovs
• #### Introduction to data encryption

Oct 4, 2014 | by Raivis Strogonovs
• #### MEMS (Part 2) – Guide to using gyroscope L3G4200D

Jun 17, 2014 | by Raivis Strogonovs
• #### seo in nRF51 Makefile with Qt Creator

thanksssssssssssssssssssss gfhfgjg

gfhfgjg

#### Rick Simpsonoil Meds in Strain Gauge based weight sensor (load cell)

Rick Simpson Oil (RSO) is a full spectrum extract of cannabis oil. It is a highly concentrated cannabis oil that contains all compounds from the cannabis plant in the extraction. It is also commonly known as Rick Simpson Oil, named after Rick Simpson who developed the product that helped...

#### Rick Simpsonoil Meds in Strain Gauge based weight sensor (load cell)

Rick Simpson Oil (RSO) is a full spectrum extract of cannabis oil. It is a highly concentrated cannabis oil that contains all compounds from the cannabis plant in the extraction. It is also commonly known as Rick Simpson Oil, named after Rick Simpson who developed the product that helped...

#### Johannes Adendorff in Simple TLS/SSL SMTP client for Qt5

DId you get BCC or CC that working?

#### Johannes Adendorff in Simple TLS/SSL SMTP client for Qt5

DId you get BCC or CC that working?

#### Sagie Meshulam in MEMS (Part 1) - Guide to using accelerometer ADXL345

Do you know if I can use flexiplot and Visual Code using C++? if so, how