[qt] envoi auto de mail hebdomadaire

Soyez le premier à donner votre avis sur cette source.

Vue 7 978 fois - Téléchargée 3 129 fois

Description

Ce programme permet d'envoyer un mail de façon hebdomadaire.
Il est basé sur le framework Qt (exécutable compilé sous Gnome, Qt 4.8).

Il utilise le protocole ASMTP, aussi connu sous le nom de SMTP AUTH (Simple Mail Transfert Protocol with Authentification) pour envoyer le mail (facilement modifiable pour utiliser simplement le protocole SMTP sans authentification). Le protocole est implémenté à l'aide de QTcpSocket. Ce protocole permet l'ajout d'une pièce jointe. Les données (sujet, corps et pièce jointe du mail) sont encodés en base64. Le mail est donc envoyé en "multipart" (voir les MIME-Type pour plus d'infos). Le programme prend en charge du texte riche pour le corps du message.

L'horloge est réalisée avec un QTimer, avec un timeout de 1 seconde. Un widget permet de connaitre l'état de l'envoi du mail,les erreurs, ou simplement le temps restant avant l'envoi du mail.

Il est possible de tester les identifiants du compte mail, et d'envoyer un mail de test. L'adresse mail de départ nécessite un mot de passe.

PS: Il s'agit de la première source que je publie, donc soyez critique si ça ne va pas ;)

Sources:
Qt
Icones: http://www.softicons.com/

Source / Exemple :


#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    srand(QDateTime::currentDateTime().toTime_t());

    set=new QSettings("options.ini", QSettings::IniFormat, this);

    tray=new QSystemTrayIcon(QIcon(":/Mail.png"), this);
    tray->show();
    connect(tray, SIGNAL(messageClicked()), this, SLOT(show()));
    connect(tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
    tray->setContextMenu(new QMenu("Menu", this));
    connect(tray->contextMenu()->addAction("Afficher"), SIGNAL(triggered()), this, SLOT(show()));
    connect(tray->contextMenu()->addAction("Quitter"), SIGNAL(triggered()), qApp, SLOT(quit()));

    widStatus=new WidStatus();

    setupUI();
    show();

    QTimer* timer=new QTimer(this);
    timer->setInterval(1000);
    connect(timer, SIGNAL(timeout()), this, SLOT(checkTime()));
    timer->start();
}

MainWindow::~MainWindow()
{
    delete ui;
    delete set;
    delete tray;
    delete widStatus;
}

void MainWindow::readyRead()
{
    QTcpSocket* socket=(QTcpSocket*)sender();
    buffer+=socket->readAll();
    if(!buffer.endsWith("\n"))
        return;
    if(status==Send::HELO)
    {
        if(buffer.startsWith("220"))
        {
            status=Send::AUTH;
            buffer.clear();
            socket->write("HELO there\n");
        }
        else
            showError("Réponse inconnue du serveur (1)", socket);
        return;
    }
    else if(status==Send::AUTH)
    {
        if(buffer.startsWith("250"))
        {
            status=Send::MAIL_FROM;
            buffer.clear();
            widStatus->showStatus("Connecté. Authentification...");
            socket->write("auth plain "+QByteArray(QByteArray("\x00", 1)+user().toStdString().c_str()+QByteArray("\x00", 1)+pass().toStdString().c_str()).toBase64()+"\n");
        }
        else
            showError("Réponse inconnue du serveur (2)", socket);
        return;
    }
    else if(status==Send::MAIL_FROM)
    {
        if(buffer.startsWith("235"))
        {
            buffer.clear();
            if(sendType!=Send::TEST_PARAMS)
            {
                status=Send::RCPT_TO;
                if(sendType!=Send::SEND_ME_RCPT)
                    widStatus->showStatus("Authentifié. Envoi du mail...");
                else if(sendType==Send::SEND_ME_RCPT)
                    widStatus->showStatus("Authentifié. Envoi des mails...");
                socket->write(QString("MAIL FROM:<"+user()+">\n").toStdString().c_str());
            }
            else if(sendType==Send::TEST_PARAMS)
            {
                status=Send::DISCO;
                widStatus->showStatus("Compte mail OK");
                socket->write("quit\n");
            }
        }
        else
            showError("Mauvais mail ou mot de passe", socket);
        return;
    }
    else if(status==Send::RCPT_TO)
    {
        if(buffer.startsWith("250"))
        {
            status=Send::DATA;
            buffer.clear();
            if(sendType==Send::SEND_RCPT)
                socket->write(QString("RCPT TO:<"+rcpt()+">\n").toStdString().c_str());
            else if(sendType==Send::SEND_ME)
                socket->write(QString("RCPT TO:<"+user()+">\n").toStdString().c_str());
            else if(sendType==Send::SEND_ME_RCPT)
                socket->write(QString("RCPT TO:<"+rcpt()+">\nRCPT TO:<"+user()+">\n").toStdString().c_str());
        }
        else
            showError("Expediteur non valide", socket);
        return;
    }
    else if(status==Send::DATA)
    {
        if(buffer.startsWith("250"))
        {
            status=Send::SENDING_DATA;
            buffer.clear();
            socket->write("DATA\n");
        }
        else
            showError("Destinataire on valide", socket);
        return;
    }
    else if(status==Send::SENDING_DATA)
    {
        if(buffer.startsWith("354"))
        {
            buffer.clear();
            QString bound=boundary(15);
            QString sjt_enc="=?UTF-8?B?"+sjt().toUtf8().toBase64()+"?=";
            QString body_enc=body().toUtf8().toBase64();

            socket->write(QString("Subject: "+sjt_enc+"\r\n").toStdString().c_str());
            socket->write(QString("From: <"+user()+">\r\n").toStdString().c_str());
            if(sendType==Send::SEND_RCPT)
                socket->write(QString("To: <"+rcpt()+">\r\n").toStdString().c_str());
            else if(sendType==Send::SEND_ME)
                socket->write(QString("To: <"+user()+">\r\n").toStdString().c_str());
            else if(sendType==Send::SEND_ME_RCPT)
                socket->write(QString("To: <"+rcpt()+"> <"+user()+">\r\n").toStdString().c_str());
            socket->write("MIME-Version: 1.0\r\n");
            socket->write(QString("Content-Type: multipart/mixed; boundary=\""+bound+"\"\r\n").toStdString().c_str());
            socket->write(QString("Date: "+QDateTime::currentDateTime().toString("ddd, d MMM yyyy hh:mm:ss +0200")+"\r\n").toStdString().c_str());
            socket->write("\r\n");

            socket->write(QString("--"+bound+"\r\n").toStdString().c_str());
            socket->write("Content-Type: text/html; charset=\"UTF-8\"\r\n");
            socket->write("Content-Transfer-Encoding: base64\r\n");
            socket->write("\r\n");
            socket->write(QString(body_enc+"\r\n").toStdString().c_str());
            socket->write("\r\n");

            QFile file(filePath().replace("\\", "/"));

            if(file.exists()&&file.open(QIODevice::ReadOnly))
            {
                widStatus->showStatus("Envoi de la pièce jointe: 0%...");
                socket->write(QString("--"+bound+"\r\n").toStdString().c_str());
                QString filePath_enc="=?UTF-8?B?"+filePath().split("/").last().toUtf8().toBase64()+"?=";
                QString mime="application/octet-stream";
                if(filePath().contains(QRegExp("\\.xls[x]{0,1}$")))
                    mime="application/vnd.ms-excel";
                if(filePath().contains(QRegExp("\\.doc[x]{0,1}$")))
                    mime="application/vnd.msword";
                if(filePath().contains(QRegExp("\\.pdf$")))
                    mime="application/pdf";

                socket->write(QString("Content-Type: "+mime+"\r\n").toStdString().c_str());
                socket->write("Content-Transfer-Encoding: base64\r\n");
                socket->write(QString("Content-Disposition: attachment; filename=\""+filePath_enc+"\"\r\n").toStdString().c_str());
                socket->write("\r\n");
                int p=0;
                QByteArray data=file.readAll();
                data=data.toBase64();
                for(int i=0;i<data.size();i++)
                {
                    if(i*100/data.size()!=p)
                    {
                        p=i*100/data.size();
                        widStatus->showStatus("Envoi de la pièce jointe: "+QString::number(p)+"%...");
                    }
                    socket->write(QByteArray().append(data.at(i)));
                    while(socket->waitForBytesWritten(50))
                        qApp->processEvents();

                }
                socket->write("\r\n\r\n");

            }
            else
            {
                showError("Fichier imossible à ouvrir", socket);
                return;
            }
            socket->write(QString("--"+bound+"--\r\n").toStdString().c_str());

            status=Send::QUIT;
            socket->write(".\r\n");
        }
        else if(sendType==Send::SEND_ME_RCPT)
        {
            if(!buffer.startsWith("250"))
                showError("Expediteur non valide", socket);
            buffer.clear();
        }
        else
            showError("Impossible d'envoyer le corps du mail", socket);
        return;
    }
    else if(status==Send::QUIT)
    {
        if(buffer.startsWith("250"))
        {
            status=Send::DISCO;
            buffer.clear();
            if(sendType!=Send::SEND_ME_RCPT)
                widStatus->showStatus("Mail envoyé. Déconnection...");
            else if(sendType==Send::SEND_ME_RCPT)
                widStatus->showStatus("Mails envoyés. Déconnection...");
            socket->write("quit\n");
        }
        else
            showError("Données invalides envoyées", socket);
        return;
    }
    else if(status==Send::DISCO)
    {
        if(buffer.startsWith("221"))
        {
            setEnabled(true);
            if(sendType==Send::TEST_PARAMS)
                widStatus->showSuccess("Compte mail valide");
            else if(sendType==Send::SEND_ME_RCPT)
                widStatus->showSuccess("Mails tests envoyés");
            else
                widStatus->showSuccess("Mail test envoyé");
            buffer.clear();
            socket->disconnect();
            socket->deleteLater();
        }
        else
            showError("Commande de déconnection refusée", socket);
        return;
    }
}

void MainWindow::error(QAbstractSocket::SocketError)
{
    widStatus->show();
    widStatus->showError(((QTcpSocket*)sender())->errorString());
}

QString MainWindow::boundary(int lenght)
{
    QString chars="AZERTYUIOPQSDFGHJKLMWXCVBNazertyuiopqsdfghjklmwxcvbn0123456789";
    QString b="";
    for(int l=0;l<lenght;l++)
        b+=chars.at(qMax(qMin(((double)chars.size()-1), ((double)rand())*chars.size()/RAND_MAX), (double)0));

    return "_"+b+"_";
}

void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason r)
{
    if(r!=QSystemTrayIcon::Context)
        show();
}

void MainWindow::on_grpFilePath_toggled(bool arg1)
{
    if(!arg1)
        ui->lineFilePath->clear();

}

void MainWindow::on_btnBrowseFilePath_clicked()
{
    QString file=QFileDialog::getOpenFileName(this, "Fichier à joindre...");
    if(!file.isEmpty())
        ui->lineFilePath->setText(file);
}

void MainWindow::on_buttonBox_accepted()
{
    set->setValue("User", ui->lineUser->text());
    set->setValue("Pass", ui->linePass->text());
    set->setValue("Rcpt", ui->lineRcpt->text());
    set->setValue("FilePath", ui->lineFilePath->text());
    set->setValue("Sjt", ui->lineSjt->text());
    set->setValue("Body", ui->lineBody->toHtml());
    set->setValue("Day", ui->comboDay->currentIndex());
    set->setValue("Hour", ui->lineHour->time());
}

void MainWindow::send()
{
    if(!isEnabled())
        return;
    setEnabled(false);
    widStatus->show();
    widStatus->showStatus("Connection...");
    status=Send::HELO;
    QTcpSocket* sock=new QTcpSocket(this);
    connect(sock, SIGNAL(readyRead()), this, SLOT(readyRead()));
    connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
    sock->connectToHost("smtpauth.orange.fr", 25);
}

void MainWindow::setupUI()
{
    ui->lineUser->setText(user());
    ui->linePass->setText(pass());
    ui->lineRcpt->setText(rcpt());
    ui->lineFilePath->setText(filePath());
    ui->lineSjt->setText(sjt());
    ui->lineBody->setHtml(body());
    ui->grpFilePath->setChecked(!filePath().isEmpty());
    ui->comboDay->setCurrentIndex(day());
    ui->lineHour->setTime(hour());
}

void MainWindow::on_buttonBox_rejected()
{
    setupUI();
}

void MainWindow::closeEvent(QCloseEvent *e)
{
    if(!qApp->arguments().contains("-indev"))
    {
        e->ignore();
        hide();
    }
    else
        e->accept();
}

void MainWindow::keyPressEvent(QKeyEvent *e)
{
    if(e->key()==Qt::Key_Return||e->key()==Qt::Key_Enter)
        on_buttonBox_accepted();
}

void MainWindow::checkTime()
{
    QDateTime next=QDateTime::currentDateTime();
    while(next.date().dayOfWeek()!=day()+1)
        next=next.addDays(1);
    if(QDateTime::currentDateTime().time()>hour())
        next=next.addDays(7);
    next.setTime(hour());

    int remaining=QDateTime::currentDateTime().secsTo(next);
    QTime re;
    re=re.addSecs(remaining);
    if(remaining==3599)
        widStatus->show();
    if(remaining<=3599&&remaining>3585)
        widStatus->showRemainingTime(re);
    else if(remaining==3585)
        widStatus->hide();

    else if(remaining==1800)
        widStatus->show();
    if(remaining<=1800&&remaining>1785)
        widStatus->showRemainingTime(re);
    else if(remaining==1785)
        widStatus->hide();

    else if(remaining==600)
        widStatus->show();
    if(remaining<=600)
    {
        widStatus->showRemainingTime(re);
        if(remaining==0)
        {
            sendType=Send::SEND_RCPT;
            send();
        }
    }

    //qDebug()<<"Current:"<<QDateTime::currentDateTime()<<"Next:"<<remaining;
}

void MainWindow::showError(QString erreur, QTcpSocket *socket)
{
    qDebug()<<"ERREUR:"<<buffer;
    setEnabled(true);
    widStatus->show();
    widStatus->showError(erreur);
    socket->disconnect();
    socket->deleteLater();
    buffer.clear();
}

void MainWindow::on_btnTestUser_clicked()
{
    on_buttonBox_accepted();
    sendType=Send::TEST_PARAMS;
    send();
}

void MainWindow::on_btnTestMail_clicked()
{
    on_buttonBox_accepted();
    DlgMailTest* test=new DlgMailTest(this);
    if(test->exec()==QDialog::Accepted)
    {
        if(test->getUi()->radioMe->isChecked())
            sendType=Send::SEND_ME;
        else if(test->getUi()->radioMeRcpt->isChecked())
            sendType=Send::SEND_ME_RCPT;
        else if(test->getUi()->radioRcpt->isChecked())
            sendType=Send::SEND_RCPT;
        send();
    }
}

void MainWindow::on_lblBody_linkActivated(const QString &link)
{
    if(link=="richText")
    {
        DlgRichText* t=new DlgRichText(this);
        t->setText(ui->lineBody->toHtml());
        if(t->exec()==QDialog::Accepted)
            ui->lineBody->setHtml(t->getText());
        t->deleteLater();
    }
}

Conclusion :


Cette source peut donc servir de base pour implémenter le protocole (A)SMTP, ou simplement une action hebdomadaire.
En espérant que ça aide quelqu'un ;)

Codes Sources

A voir également

Ajouter un commentaire Commentaires
Messages postés
7
Date d'inscription
samedi 8 mars 2008
Statut
Membre
Dernière intervention
29 septembre 2009

Bonjour,
Le problème est que gmail (ainsi que d'autres) force à utiliser une connexion sécurisé SSL, la seule chose à changer (a priori) serait de changer la ligne 304, et remplacer new QTcpSocket par new QSslSocket, et bien évidemment, l'adresse du serveur :)
Bonjour, j'ai essayer mail avec Gmail en modifiant la ligne 307, en utilisant "smtp.gmail.com" mais malheureusement je m'ai pas de réponse lorsque je teste l'adresse.
Messages postés
7
Date d'inscription
samedi 8 mars 2008
Statut
Membre
Dernière intervention
29 septembre 2009

Bah, ça fait beaucoup tout ça^^ tu risque effectivement de te faire kick, soit par un parfeu, ou un filtre anti-spam... Etant donné que cet exemple utilise ASMTP, et pas juste SMTP, il est cependant possible que ça passe, après, pour ta liste de 'contact', là, c'est toi qui gère ;)
Messages postés
3
Date d'inscription
samedi 31 mai 2003
Statut
Membre
Dernière intervention
13 juillet 2012

Bonjour et merci pour ta réponse. En effet je suis chez Free et il bloque visiblement l' accès à un autre smtp. Mon objectif est de créer une application d' envoi d' Email différents et en nombre ( < 500000/mois ). Pas du spam bien entendu, mais la nuance semble difficile à démontrer aux différents filtres du réseau. Une expérience dans ce domaine ? sachant que je n'ai pas de serveur dédié.
Messages postés
7
Date d'inscription
samedi 8 mars 2008
Statut
Membre
Dernière intervention
29 septembre 2009

Bonjour, le problème vient surement du fait que le serveur smtp est hardcoded, si tu n'est pas chez orange, c'est presque normal que ça ne fonctionne pas, les parefeu des box bloquent les serveurs smtp qui ne sont pas les leurs. Il suffit simplement de changer l'adresse du serveur à la ligne 307 ==> smtpauth.orange.fr, en la remplacant par votre FAI, dispo ici: http://www.commentcamarche.net/faq/893-adresses-des-serveurs-pop-et-smtp-des-principaux-fai
Afficher les 6 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.