Russian Qt Forum
Апрель 25, 2024, 04:00 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3 4   Вниз
  Печать  
Автор Тема: Отправка сообщений по протоколу SMTP  (Прочитано 44134 раз)
merke
Гость
« : Сентябрь 08, 2010, 17:11 »

Несколько раз требовалось в программах реализовать отправку писем именно по протоколу SMTP, блуждал по форумам и ни как не мог найти существенной - простой реализации на кутях. Выбив маленько времени в графике решил написать свой класс, дабы в следующий раз не усложнять себе жизнь.

Выкладываю исходники класса. В приложении будет релиз консольного приложения.

smtp.h

Код:
#ifndef SMTP_H
#define SMTP_H

#include <QTcpSocket>
#include <QTextStream>

class smtp : public QObject
{
    Q_OBJECT
    
public:
    smtp(QString host, quint16 port);
    ~smtp();
    
    void set_Login(QString login); //Задаем логин
    void set_Password_for_login(QString password);//Задем пароль
    void set_Sender_mail(QString email);//Задаем отправителя
    void set_Recipient_mail(QString email);//Задаем получателя
    void set_Body_text(QString text);//Задаем текст тела сообщения
    void set_Subject(QString subject);//Задаем тему сообщения
    void send_Mail();//Отправка сообщенич
    
private:
    
    QString p_host;
    quint32 p_port;
    QString p_login;
    QString p_password;
    QString p_mail_From;
    QString p_mail_to;
    QString p_body;
    QString p_subject;
    
    QString message;
    
    int state;
    QString response;
    
    QTcpSocket *tcp;
    QTextStream *t;
    QString encodeBase64( QString xml );
    QString decodeBase64( QString xml );
    
  
    
    enum State {
            Init,  //Инициализация
            Start,
            Login,//Логин
            Pass, //Пароль
            Mail, //Отправитель
            Rcpt, //Получатель
            Data,
            Body, //Тело
            Quit,
            Close
        };

    
private slots:
    void on_connected();
    void on_read();

signals:
    void error_code(QString error_text);  
    void status( const QString & );
};

#endif // SMTP_H

smtp.cpp

Код:
#include <smtp.h>

smtp::smtp(QString host, quint16 port)
{

    p_host = host;
    p_port = port;
    tcp = new QTcpSocket();//Создаем экземляр объекта сокета
    t = new QTextStream(tcp);
    

    connect(tcp, SIGNAL(connected()),this, SLOT(on_connected()));
    connect(tcp, SIGNAL(readyRead()), this, SLOT(on_read()));
    connect(this, SIGNAL(status(QString)), this, SLOT(message_sended(QString)));
}

smtp::~smtp()
{

}


void smtp::send_Mail()
{
    if (p_login.isEmpty() || p_password.isEmpty())
        {
            emit error_code(QString::fromLocal8Bit("Логин или пароль не установлены"));
            return;
        }
    if (p_mail_From.isEmpty() || p_mail_to.isEmpty())
        {
            emit error_code(QString::fromLocal8Bit("Получатель или отправитель не задан"));
            return;
        }
    if (p_body.isEmpty())
        {
            emit error_code(QString::fromLocal8Bit("Тело сообщения не задано"));
            return;
        }
    if (p_subject.isEmpty())
        {
            emit error_code(QString::fromLocal8Bit("Тема сообщения не задана"));
            return;
        }
    
    tcp->abort();
    tcp->connectToHost(p_host, p_port);
    state = Init;
}

void smtp::on_connected()
{
    emit status("Connected to SMTP server");
}

void smtp::on_read()
{
    if( !tcp->canReadLine() )
        return;
    
    QString responseLine;
    
    do {
            responseLine = tcp->readLine();
            response += responseLine;
        } while( tcp->canReadLine() && responseLine[3] != ' ' );
    qDebug() << responseLine;
    responseLine.truncate( 3 );
    
    if ( state == Init && responseLine[0] == '2' )
        {
            
            *t << "HELO there\r\n";
            t->flush();
            state = Start;
        }
    else if (state == Start && responseLine[0] == '2')
        {
            *t << "AUTH LOGIN\r\n";
            t->flush();
            state = Login;
        }
    else if (state == Login && responseLine[0] == '3')
        {
            *t << encodeBase64(p_login) << "\r\n";
            t->flush();
            state = Pass;
        }
    else if (state == Pass && responseLine[0] == '3')
        {
            *t << encodeBase64(p_password) << "\r\n";
            t->flush();
            state = Mail;
        }
    else if ( state == Mail && responseLine[0] == '2' )
        {
            
            *t << "MAIL FROM: <" << p_mail_From << ">\r\n";
            t->flush();
            state = Rcpt;
        }
    else if ( state == Rcpt && responseLine[0] == '2' )
        {
            
            *t << "RCPT TO: <" << p_mail_to << ">\r\n";
            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' )
        {
            QString body;
            body = p_body;
            QString subject;
            subject = p_subject;
            message = QString::fromLatin1( "From: " ) + p_mail_From
                      +QString::fromLatin1( "\nTo: " ) + p_mail_to +QString::fromLatin1( "\nSubject: "
                                                                                                       ) + subject +QString::fromLatin1( "\n\n" ) + body +"\n";
            message.replace( QString::fromLatin1( "\n" ), QString::fromLatin1(
                    "\r\n" ) );
            message.replace( QString::fromLatin1( "\r\n.\r\n" ),
                             QString::fromLatin1( "\r\n..\r\n" ) );
            
            *t << message << "\n" << ".\r\n";
            t->flush();
            state = Quit;
        }
    else if ( state == Quit && responseLine[0] == '2' )
        {
            *t << "QUIT\r\n";
            state = Close;
            //t->flush();
            emit status( tr( "Message sent" ) );
        }
    else if ( state == Close )
        {
            
        }
    else
        {
            emit status(tr("Unknown answer from SMTP server"));
            state = Close;
        }
    response = "";  
}

void smtp::set_Login(QString login)
{
    p_login = login;
}

void smtp::set_Password_for_login(QString password)
{
    p_password = password;
}

void smtp::set_Sender_mail(QString email)
{
    p_mail_From = email;
}

void smtp::set_Recipient_mail(QString email)
{
    p_mail_to = email;
}

void smtp::set_Body_text(QString text)
{
    p_body = text;
}

void smtp::set_Subject(QString subject)
{
    p_subject = subject;
}

QString smtp::encodeBase64( QString xml )
{
    QByteArray text;
    text.append(xml);
    return text.toBase64();
}

QString smtp::decodeBase64( QString xml )
{
    QByteArray xcode("");;
    xcode.append(xml);
    QByteArray precode(QByteArray::fromBase64(xcode));
    QString notetxt = precode.data();
    return notetxt;
}


Пример простой отправки:

  
Код:
 smtp *mail = new smtp("smtp.mail.ru", 25);
    mail->set_Login("mylnik@mail.ru");
    mail->set_Password_for_login("123456");
    mail->set_Sender_mail("mylnik@mail.ru");
    mail->set_Recipient_mail("vasya@mail.ru");
    mail->set_Subject(QString::fromLocal8Bit("Привет"));
    mail->set_Body_text("HI");
    mail->send_Mail();

Код может быть и не универсален! Жду критику=)


Поменять расширение вложения на .rar



« Последнее редактирование: Сентябрь 08, 2010, 18:04 от Александр » Записан
Amigo_sa
Гость
« Ответ #1 : Сентябрь 08, 2010, 17:59 »

очень полезный для меня класс, спасибо!
Пожелание, не могли бы вы выложить файл проекта, а то многие mingwm не имеют =). Хотя я и так код ручками копировал)
Записан
merke
Гость
« Ответ #2 : Сентябрь 08, 2010, 18:03 »

Вот вам сорсы, во вложении изменить расширение на .rar
Записан
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #3 : Сентябрь 08, 2010, 19:02 »

Код
C++ (Qt)
QString::fromLatin1( "From: " ) + p_mail_From+QString::fromLatin1( "\nTo: " ) + p_mail_to +QString::fromLatin1( "\nSubject: ") + subject +QString::fromLatin1( "\n\n" ) + body +"\n";
 

Этож песец так писать.. Не удержался ) Рекомендую глянуть в сторону функции QString::arg

Код
C++ (Qt)
QString( "From: %1\nTo: %2\nSubject: %3\n\n%4\n" ).arg(p_mail_From).arg(p_mail_to).arg(subject).arg(body);
 
Записан

Гугль в помощь
merke
Гость
« Ответ #4 : Сентябрь 08, 2010, 19:33 »

окей, учту! Да блин несколько лет писал на VB и всё остаются привычки=)
Записан
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #5 : Сентябрь 08, 2010, 19:45 »

Видно что недавно на сях )

Вижу утечки:
Код:
smtp::smtp(QString host, quint16 port)
{
    ...
    tcp = new QTcpSocket();//Создаем экземляр объекта сокета
    t = new QTextStream(tcp);
    ...
}

smtp::~smtp()
{
    ???? пусто
}
Записан

Гугль в помощь
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #6 : Сентябрь 08, 2010, 20:02 »

есть некий проект, но я не помню как зовется что-то типа qmp или qsmtp. Короче набор классов для работы с почтой, включая самописный сервак на Qt, реализацию pop, imap, smtp
Записан
Amigo_sa
Гость
« Ответ #7 : Сентябрь 08, 2010, 21:50 »

Видно что недавно на сях )

Вижу утечки:
Код:
smtp::smtp(QString host, quint16 port)
{
    ...
    tcp = new QTcpSocket();//Создаем экземляр объекта сокета
    t = new QTextStream(tcp);
    ...
}

smtp::~smtp()
{
    ???? пусто
}
Конечно это потенциальная ошибка, но если по логике программы класс smtp живет вместе с процессом всегда, то не страшно.
Записан
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #8 : Сентябрь 08, 2010, 23:39 »

Цитировать
Конечно это потенциальная ошибка, но если по логике программы класс smtp живет вместе с процессом всегда, то не страшно.

Только потом, когда смотришь как кутэ течет, да как визуальные стили текут (qtcurve да oxygen), да остальные системные либы... переходы по не инициализированным переменным пачками...  не по себе как-то. Они видимо тоже так думают Улыбающийся
Записан

Гугль в помощь
vadim303
Гость
« Ответ #9 : Сентябрь 09, 2010, 09:43 »

Видно что недавно на сях )

Вижу утечки:
Код:
smtp::smtp(QString host, quint16 port)
{
    ...
    tcp = new QTcpSocket();//Создаем экземляр объекта сокета
    t = new QTextStream(tcp);
    ...
}

smtp::~smtp()
{
    ???? пусто
}
Конечно это потенциальная ошибка, но если по логике программы класс smtp живет вместе с процессом всегда, то не страшно.
Чем хорош Qt - его классы спроектированы так, что сами удаляют из памяти все дочерние объекы, надо только не забывать у них parent указывать в конструкторе (если только это не визуальные объекты которые потом с помощью методов типа addWidget добавляют - тогда не обязательно и это). Если лень delete прописывать, достаточно в вашем случае указать в конструкторе родителя: QTcpSocket(this)

Edit:
Ну и чтобы ваш класс было так же удобно использовать, сделайте конструктор как полагается:
в smtp.h:
Код:
smtp(QString host, quint16 port, QObject *parent = 0);
в smtp.cpp:
Код:
smtp::smtp(QString host, quint16 port, QObject *parent) : QObject(parent)
{
  ...
« Последнее редактирование: Сентябрь 09, 2010, 09:53 от vadim303 » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #10 : Сентябрь 09, 2010, 13:55 »

navrocky
а чем вы меряли утечки, простите? лично я их в Qt не нашел (вру, нашел 1). Возможно ваша тулза таки неправильно показывает?
Записан
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #11 : Сентябрь 09, 2010, 16:15 »

Цитировать
а чем вы меряли утечки, простите? лично я их в Qt не нашел (вру, нашел 1). Возможно ваша тулза таки неправильно показывает?
Под линуксом - valgrind. Обычно он не ошибается. Часто кажется что он врет, но после долгих раскопок все-таки находишь )
Записан

Гугль в помощь
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #12 : Сентябрь 09, 2010, 16:31 »

он врет:)
он тупит из-за статик переменных, насколько я знаю.
Записан
varkon
Гость
« Ответ #13 : Сентябрь 09, 2010, 17:47 »

он врет:)
он тупит из-за статик переменных, насколько я знаю.
а есть принципиальная разница - врет он или нет? Или в Qt реализован сборщик мусора? Оба ответа  - нет.
Выделенные ресурсы надо освобождать, либо использовать "умные указатели". Подход - "но если по логике программы ...." - был, есть и будет основным источником ошибок в приложениях.
З.Ы. Это относится к данному конкретному коду, а не к высказыванию о массовости memory licks от navrocky. Хотя в целом не так уж он и неправ. 
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #14 : Сентябрь 09, 2010, 17:57 »

я про Qt веду речь:) а в данном коде да, утечка и никакие "логики" ее не оправдывают
Записан
Страниц: [1] 2 3 4   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.104 секунд. Запросов: 22.