+ Répondre à la discussion Actualité déjà publiée
Affichage des résultats 1 à 12 sur 12
  1. #1
    Expert Confirmé Sénior


    Homme Profil pro
    Étudiant
    Inscrit en
    décembre 2011
    Messages
    5 109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 21
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : décembre 2011
    Messages : 5 109
    Points : 15 177
    Points
    15 177

    Par défaut [Tutoriel] Vérification et envoi d'e-mail en C++ avec boost, par Neckara

    Bonjour,

    Je vous présente ici mon article Vérification et envoi d'e-mail en C++ avec boost.

    Ce tutoriel vous montre comment vérifier puis envoyer des e-mails en C++ avec boost mais vous pouvez très bien reprendre et adapter l'algorithme pour envoyer des e-mails avec d'autres langages ou bibliothèques.
    Bonne lecture,

    Neckara

  2. #2
    Expert Confirmé Sénior


    Homme Profil pro
    Étudiant
    Inscrit en
    décembre 2011
    Messages
    5 109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 21
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : décembre 2011
    Messages : 5 109
    Points : 15 177
    Points
    15 177

    Par défaut

    Correction de la recherche des serveurs DNS sous Windows.

    J'avais oublié de rajouter defined __WIN32 || defined __WIN64 donc bien évidement, lors des tests le code marchait parfaitement vu qu'il utilisait les serveurs DNS de google

    J'ai donc corrigé les erreurs, le code devrait désormais être bon.

    Désolé

  3. #3
    Invité de passage
    Homme Profil pro
    Développeur informatique
    Inscrit en
    janvier 2013
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : janvier 2013
    Messages : 1
    Points : 1
    Points
    1

    Par défaut Erreur de nommage

    Bonjour,

    J'ai lu votre tuto avec intérêt, mais il y a des erreurs dans le nommage des variables ou des oublis je ne sais pas. Dans plusieurs fonction la variable "result" apparait sans jamais avoir était déclaré. Ensuite il y a des erreurs de frappe dans la plus part des fonctions.
    Je doute que vous ayez réussit à compiler votre programme, pas cette version en tout cas.

    Tuto intéressants mais inexploitable correctement, il est difficile de tout comprendre.

    cdt

  4. #4
    Expert Confirmé Sénior


    Homme Profil pro
    Étudiant
    Inscrit en
    décembre 2011
    Messages
    5 109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 21
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : décembre 2011
    Messages : 5 109
    Points : 15 177
    Points
    15 177

    Par défaut

    Bonjour,

    En effet, je me suis joliment planté.
    J'avais effectivement une version qui compilait que j'ai dû copier/coller et séparer en sous-fonctions pour l'article.

    J'avais rédiger cet article assez rapidement, honte à moi d'avoir oublié de tester le code.
    Dommage que ces erreurs soient passées au travers de la relecture technique .

    Pour la II.B.2, dans l'article originale, il y avait une liste à deux niveaux :
    • partie locale :
      • tout sauf '@' : [^@]
      • avec au minimum un caractère : [^@]+

    • caractère séparateur : '@'
    • nom de domaine :
      • tout sauf '@' : [^@]
      • au moins un caractère : [^@]+
      • un '.' : \.
      • au moins deux caractères qui ne sont pas des '@' : [^@]{2,}

    Je ne sais pas si cette erreur est présente depuis le début ou si elle a été introduite lors d'une régénération automatique de l'article.

    Pour "result" (erreur lors du découpage de mes fonctions) :
    • dans "getXMServerFromAnswer", c'est "answer" ;
    • dans "hostToString", c'est le "answer" de "getXMServerFromAnswer".


    Après, il ne faut pas non plus hésiter à consulter les liens que je donne pour comprendre par exemple la structure de la réponse du serveur DNS.
    Mais c'est vrai qu'il faudrait mettre à jour 2-3 choses.

    Malheureusement, je ne peux plus vraiment corriger l'article, donc si un rédacteur ou une personnes motivée est prête à reprendre cet article, je peux lui passer la version odt finale.
    Sinon, tu peux aussi envoyer un e-mail à la rédaction pour demander la correction de l'article.

  5. #5
    Invité régulier
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : novembre 2014
    Messages : 7
    Points : 5
    Points
    5

    Par défaut

    Bonjour,

    Je suis en train de chercher des infos sur la façon d'envoyer des mails via boost en C++.
    Donc merci pour ce tuto intéressant. Mais effectivement, dommage qu' il y ai plusieurs erreurs dans le code publié ( variables ... ). Si vous avez encore la version qui compilait, est il possible d'en obtenir le code ?

    Sinon, qu'est ce que la fonction verifyResponse() dans la fonction sendMail() ?

    Merci,

    Asu

  6. #6
    Expert Confirmé Sénior


    Homme Profil pro
    Étudiant
    Inscrit en
    décembre 2011
    Messages
    5 109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 21
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : décembre 2011
    Messages : 5 109
    Points : 15 177
    Points
    15 177

    Par défaut

    Bonjour,

    Citation Envoyé par Asubayo Voir le message
    Si vous avez encore la version qui compilait, est il possible d'en obtenir le code ?
    Je ne peux malheureusement pas fournir le code tel quel.
    Mais vous pouvez tout simplement copier-coller le code de l'article puis de corriger les erreurs données par le compilateur.
    A par pour le "result" de "hostToString", le reste devrait être trivial.

    Je vais tout de même essayer de corriger quelques erreurs de compilations et de vous donner un petit code ici même.
    Après, le but de l'article était surtout de vous expliquer le fonctionnement d'un envoie d'e-mail, pas de donner un code prêt à l’emploi à copier/coller.
    En effet, il y aurait plusieurs choses à améliorer :
    • regrouper les fonctions dans une classe d'envoi de mails ;
    • éviter certains "nombres magiques", etc.


    Mais c'est vrai que d'avoir une version compilable ne serait pas du luxe .

    Sinon, qu'est ce que la fonction verifyResponse() dans la fonction sendMail() ?
    Quand on envoie une requête au serveur SMTP, on reçoit une réponse, il faut donc lire la réponse et vérifier qu'il n'y ai pas eu d'erreurs :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
            bool verifyResponse(const std::string & responseWaited, boost::asio::ip::tcp::socket & socket)
            {
                bool retour = true;
     
                boost::asio::streambuf response;
                std::string code;
     
                boost::asio::read_until(socket, response, "\r\n");
                {
                    std::istream is(&response);
                    is >> code;
                    if( code != responseWaited)
                    {
                        std::cerr << "Réponse du serveur SMTP inattendu" << std::endl;
                        retour = false;
                    }
     
                    response.consume( response.size() );
     
                    boost::asio::socket_base::bytes_readable command(true);
                    socket.io_control(command);
                    while( command.get() )
                    {
                        boost::asio::read_until(socket, response, "\r\n");
                        socket.io_control(command);
                    }
                    response.consume( response.size() );
     
                }
     
                return retour;
            }
    Sinon, d'où vient cet intérêt soudain pour mon article ? ^^

  7. #7
    Expert Confirmé Sénior


    Homme Profil pro
    Étudiant
    Inscrit en
    décembre 2011
    Messages
    5 109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 21
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : décembre 2011
    Messages : 5 109
    Points : 15 177
    Points
    15 177

    Par défaut

    Je n'ai pas testé l'édition des liens, mais voici une version qui aura un peu moins d'erreurs :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    #include <string>
    #include <vector>
    #include <boost/asio.hpp>
    #include <boost/array.hpp>
     
    #if defined WIN32 || defined WIN64 || defined _WIN32_ || defined _WIN64_ || defined __WIN32 || defined __WIN64
        #define WINDOWS
    #endif
     
    #ifdef WINDOWS
        #include <windows.>
        #include <iphlpapi.h>
        #pragma comment(lib, "IPHLPAPI.lib")
    #endif
     
           bool verifyResponse(const std::string & responseWaited, boost::asio::ip::tcp::socket & socket)
            {
                bool retour = true;
     
                boost::asio::streambuf response;
                std::string code;
     
                boost::asio::read_until(socket, response, "\r\n");
                {
                    std::istream is(&response);
                    is >> code;
                    if( code != responseWaited)
                    {
                        std::cerr << "Réponse du serveur SMTP inattendu" << std::endl;
                        retour = false;
                    }
     
                    response.consume( response.size() );
     
                    boost::asio::socket_base::bytes_readable command(true);
                    socket.io_control(command);
                    while( command.get() )
                    {
                        boost::asio::read_until(socket, response, "\r\n");
                        socket.io_control(command);
                    }
                    response.consume( response.size() );
     
                }
     
                return retour;
            }
     
    std::vector<std::string> getDNS(void)
    {
         std::vector<std::string> dns_names;
         #ifdef WINDOWS
                 // Structure qui contiendra les informations que l'on recherche.
                FIXED_INFO * info = (FIXED_INFO *)malloc( sizeof(FIXED_INFO) );
     
                ULONG bufferSize = sizeof(info); // Taille de la structure.
                DWORD retour = GetNetworkParams( info, &bufferSize );
     
                if( retour == ERROR_BUFFER_OVERFLOW ) // Si la structure n'est pas assez grande.
                {
                       info = (FIXED_INFO *)realloc(info, bufferSize);
                       retour = GetNetworkParams( info, &bufferSize );
                }
     
                // Si on a réussi à obtenir nos informations.
                if( retour == ERROR_SUCCESS)
                {
                         // On récupère la liste des serveurs DNS.
                         struct _IP_ADDR_STRING * next = &info->DnsServerList;
     
                        // On parcourt la liste des serveurs DNS.
                        while( next )
                        {
                               dns_names.push_back( next->IpAddress.String  );
                               next = next->Next;
                        }
                 }
                 free(info);
           #else
                  // pour les Unix-like, lire le fichier /etc/resolv.conf
           #endif
             // au cas où, on ajoute les serveurs DNS de Google.
            dns_names.push_back("8.8.8.8") ;
            dns_names.push_back("8.8.4.4") ;
     
            return dns_names ;
    }
     
    std::string buildDNSQuery(const std::string & mail)
    {
          // On récupère le nom de domaine.
          int i = mail.find('@');
          std::string host = mail.substr(i + 1);
          // on met un identifiant quelconque pour notre demande
          std::string dnsQueryText = "AA"; //id
     
          char octet = 0x00 ; // On envoie une requête.
          octet |= 0x00 ; // C'est une requête standard.
          octet |= 0x00 ; // Le message n'est pas tronqué.
          octet |= 0x01 ; // C'est une requête récursive.
     
          dnsQueryText += octet ;
          dnsQueryText += '\x00'; // Réservé au serveur.
     
          dnsQueryText += '\x00';
          dnsQueryText += '\x01'; // On n'a qu'une question.
     
          dnsQueryText += '\x00';
          dnsQueryText += '\x00'; // On n'a pas de réponses.
     
          dnsQueryText += '\x00';
          dnsQueryText += '\x00'; // Pas de réponses d’autorité, on s'en moque ici.
     
          dnsQueryText += '\x00';
          dnsQueryText += '\x00'; // Pas de réponses additionnelles, on s'en moque aussi ici.
          // Début de la requête.
          // On va devoir renseigner le nom de domaine, avant chaque partie du nom de domaine séparé par des « . », on va devoir mettre la taille de cette partie et ne plus mettre les « . »
          size_t pos = 0;
          size_t oldPos = 0;
     
          // On recherche tous les « . » du nom de domaine.
          while( (pos = host.find('.', pos) ) != std::string::npos )
          {
               // On met la taille de la partie.
               dnsQueryText += (char)pos - oldPos;
     
               // On ajoute la partie.
               dnsQueryText += host.substr(oldPos, pos - oldPos);
     
               pos++;
               oldPos = pos;
          }
          // On ajoute la dernière partie du nom de domaine.
          dnsQueryText += (char)(host.size() - oldPos);
          dnsQueryText += host.substr(oldPos, host.size() - oldPos );
          dnsQueryText += '\x00'; // Fin du nom de domaine.
     
          dnsQueryText += '\x00';
          dnsQueryText += '\x0f'; // On recherche un serveur SMTP.
     
          dnsQueryText += '\x00';
          dnsQueryText += '\x01'; // On utilise la classe INET.
     
          return dnsQueryText;
    }
     
    std::string askDNS( const std::string & queryText,
                                     const std::vector<std::string> & DNSnames,
                                     boost::asio::io_service & io_service )
    {
             // Socket UDP pour dialoguer avec le serveur DNS.
             boost::asio::ip::udp::socket dnsSocket(io_service);
     
             // Erreur par défaut
             boost::system::error_code dnsError = boost::asio::error::host_not_found;
     
             // Tampon pour contenir la réponse du serveur DNS.
             boost::array<char, 1024> dnsBuffer;
     
              // Trouve le serveur à partir de son nom de domaine ou de son adresse IPv4 ou IPv6 et de son port.
             boost::asio::ip::udp::resolver dns_resolver(io_service);
     
             // On va parcourir la liste des serveurs DNS tant qu'on n'a pas réussi à avoir une réponse.      
             std::vector<std::string>::const_iterator it = DNSnames.begin();
             while( dnsError && it != DNSnames.end() )
             {
                    // On recherche le serveur.
                    boost::asio::ip::udp::resolver::query dns_query(*it, "53");
                    auto dns_endpoint_iterator = dns_resolver.resolve(dns_query);
                    boost::asio::ip::udp::resolver::iterator dns_end;
     
                    // Pour chaque serveur trouvé.
                    while(dnsError && dns_endpoint_iterator != dns_end )
            {
                        // On essaye de connecter le socket UDP.
                        dnsSocket.connect( *dns_endpoint_iterator++ , dnsError);
     
                        // Si on a réussi, on lui envoie notre requête.
                        if( ! dnsError)
                        {
                            dnsSocket.send( boost::asio::buffer(queryText) ,
                                               boost::asio::socket_base::message_flags(), dnsError);
     
                            // Si pas d'erreur, on attend une réponse
                            if( ! dnsError )
                            {
                                // Si le serveur ne répond pas, on attendra indéfiniment, il faut donc penser à rajouter un timeout.
                                dnsSocket.receive( boost::asio::buffer(dnsBuffer) );
                            }
                        }
                    }
                    it++;
                }
     
                // Si on n'a pas eu de réponse, on lance une exception.
                if(dnsError)
                    throw boost::system::system_error(dnsError);
     
                // Si on a eu une réponse, on la retourne
                return std::string (dnsBuffer.c_array(), dnsBuffer.size() );
    }
     
    std::string hostnameToString(std::string hostname, const std::string &);
     
    std::vector<std::string> getXMServerFromAnswer( const std::string & answer, const std::string & query)
    {
          // On obtient le nombre de réponses :
          int nbAnswer = (answer[7] << 8) + answer[8];
     
          // On alloue le vecteur pour stocker les réponses
          std::vector<std::string> MXserver(nbAnswer);
     
          // On calcule la position du début de la première réponse
          int offset = query.size() + 1;
     
     
          // Pour chaque réponse.
          for( ; nbAnswer ; nbAnswer--)
          {
                   // On se place à la fin du nom de domaine
                   offset = answer.find('\0', offset);
     
                   // On se place après le type, la classe et le "time to live" 
                   offset += 8;
     
                   // On récupère la taille des informations supplémentaires
                   size_t size = ( (unsigned int)answer[offset] << 8) + (unsigned int)answer[offset + 1];
     
                   // On se place après la longueur des informations supplémentaires et la préférence.
                   // Vous pouvez néanmoins récupérer la préférence pour établir une priorité entre les serveurs SMTP à utiliser.
                   offset += 4;
     
                    // On récupère le nom de domaine du serveur SMTP.
                    std::string hostname = answer.substr(offset, size - 2);
     
                    // Mais ce n'est pas fini, ce nom de domaine à un format un peu particulier...
                    MXserver.push_back(  hostnameToString(hostname, answer) ) ;
           }
     
           return MXserver ;
    }
     
     
     
    std::string hostnameToString(std::string hostname, const std::string & response)
    {
                    size_t i = 0;
                    // On va parcourir notre chaîne de caractères.
                    while( i < hostname.size() )
                    {
                        // Si le caractère vaut 0xc0, cela signifie que la suite du nom de domaine est à rechercher à l'emplacement indiqué par le caractère suivant.
                        if( hostname[i] == '\xc0' )
                        {
                            // On récupère la suite du nom de domaine.
                            size_t fin = response.find('\0', (unsigned char)hostname[i+1]) - (unsigned char)hostname[i+1];
                            hostname += response.substr( (unsigned char)hostname[i+1],
                                                             fin );
     
                            // On supprime le caractère 0xc0 et celui qui suivait.
                            hostname.erase(i,2);
                        }
                        else
                        {
                            // Sinon, le caractère sur lequel nous tombons indique la longueur de la partie de nom de domaine qui suit.
                            size_t size = hostname[i];
                            if(size)
                            {
                                // On le remplace par un « . ».
                                hostname[i] = '.';
     
                                // On se place après la fin de cette partie de nom de domaine.
                                i += size + 1;
                            }
                            else
                                break; // La taille est nulle, on est arrivé à la fin.
                        }
                    }
     
                     // Les noms de domaine ne commencent pas par un « . », on le supprime donc.
                    hostname.erase(0,1);
     
                    return hostname ;
    }
     
    std::vector<std::string> getMXServer( const std::string & mail, boost::asio::io_service & io_service )
    {
             // On obtient la liste des serveurs DNS.
             std::vector<std::string> DNSnames = getDNS();
     
             // On obtient la requête à envoyer.
             std::string queryText = buildDNSQuery(mail) ;
     
             // On obtient la réponse du serveur DNS.
             std::string response = askDNS(queryText, DNSnames, io_service);
     
             // On obtient la liste des serveurs MX.
             return getXMServerFromAnswer( response, queryText) ;
    }
     
    boost::asio::ip::tcp::socket getMXSocket( std::vector<std::string> Mxnames,
                                              boost::asio::io_service & io_service )
    {
          boost::asio::ip::tcp::socket socket(io_service);
     
          boost::asio::ip::tcp::resolver resolver(io_service);
     
          // Erreur par défaut.
          boost::system::error_code error = boost::asio::error::host_not_found;
     
          auto it = Mxnames.begin() ;
          auto end = Mxnames.end() ;
     
          // Tant qu'on n'a pas réussi à se connecter, on parcourt la liste des serveurs MX.
          while( error && it != end)
          {
     
                boost::asio::ip::tcp::resolver::query query(*it, "25");
                boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
                boost::asio::ip::tcp::resolver::iterator end;
     
                // Pour chaque serveur trouvé.
                while(error && endpoint_iterator != end )
                {
                    // On essaye de se connecter au serveur.
                    socket.close();
                    socket.connect(*endpoint_iterator++, error);
                }
            ++it;
            }
     
            // Si aucun serveur n'a été trouvé.
            if( error )
                throw boost::system::system_error(error);
     
          return socket ;
    }
     
     
    void sendMail( const std::string & destinataire,
                          const std::string & expediteur,
                          const std::string & message,
                          boost::asio::ip::tcp::socket & socket )
    {
         std::string hello = "HELO Client\r\n";
         std::string exp = "MAIL FROM: <" + expediteur + ">\r\n";
         std::string dest = "RCPT TO: <" + destinataire + ">\r\n";
         std::string beginData = "DATA\r\n";
         std::string endData = "\r\n.\r\n";
         std::string quit = "QUIT\r\n";
     
         verifyResponse("220", socket);
     
         boost::asio::write(socket, boost::asio::buffer(hello) );
         verifyResponse("250", socket);
     
         boost::asio::write(socket, boost::asio::buffer(exp) );
         verifyResponse("250", socket);
     
         // Vous pouvez répéter cette action si vous souhaitez envoyer l'e-mail à plusieurs destinataires
         // dont l'adresse e-mail a le même nom de domaine.
         boost::asio::write(socket, boost::asio::buffer(dest) );
         verifyResponse("250", socket);
     
         boost::asio::write(socket, boost::asio::buffer(beginData) );
         verifyResponse("354", socket);
     
          boost::asio::write(socket, boost::asio::buffer(message) );
          boost::asio::write(socket, boost::asio::buffer(endData) );
          verifyResponse("250", socket);
     
          boost::asio::write(socket, boost::asio::buffer(quit) );
          verifyResponse("221", socket);
     
          socket.close();
    }
     
     
    std::string buildMessage( const std::string & expediteur,
                                         const std::vector<std::string> & listDestinataires,
                                         const std::string & subject,
                                         const std::string & htmlMessage,
                                         const std::string & rawMessage,
                                         const std::string & sectionWord = "08zs01293eraf47a7804dcd17b1e")
    {
            std::string message = "Mime-Version: 1.0\r\n";
     
            // On renseigne l'expéditeur.
            message += "from: automatique<" + expediteur + ">\r\n";
     
            // On renseigne tous les destinataires.
            // Ils doivent être au format alias<e-mail>, alias étant facultatif.
            // Exemple : toto<toto@foo.fr>
            for( const auto & destinataire : listDestinataires)
                    message += "to: "+ destinataire + "\r\n";
     
             // Ajout du sujet du message.
             message += "subject: " + subject + "\r\n";
     
              // On a un message contenant plusieurs formats.
              // Les différents formats seront séparés par le mot sectionWord.
             message += "Content-Type: multipart/alternative; boundary=" + sectionWord  + "\r\n";
             message += "\r\n";
     
              // Début du premier format.
              message += "\r\n--" + sectionWord  + "\r\n";
     
              // Texte brut.
              message += "Content-type: text/plain; charset=ISO-8859-1\r\n";
              message += "\r\n";
     
              // Texte brut ASCII.
              // Pensez toujours à intégrer ce format à vos messages car tous les clients de messagerie ne supportent pas le HTML.
              message += rawMessage ;
     
              message += "\r\n";
     
               // Fin de ce format et début de la prochaine.
              message += "--" + sectionWord  + "\r\n";
     
              // Texte HTML.           
              message += "Content-type: text/html; charset=ISO-8859-1\r\n";
              message += "\r\n";
     
              // Texte HTML.
              message += htmlMessage ;
     
              message += "\r\n";
     
              // Fin de l'e-mail.
              message += "\r\n--" + sectionWord  + "--\r\n";
     
            return message ;
    }
     
     
    void sendMail( const std::string & destinataire,
                         const std::string & expediteur,
                         const std::vector<std::string> & listDestinataires,
                         const std::string & subject,
                         const std::string & htmlMessage,
                         const std::string & rawMessage,
                         const std::string & sectionWord,
                         boost::asio::io_service & io_service )
    {
     
           // On construit le message
           std::string message = buildMessage( expediteur, listDestinataires, subject, htmlMessage, rawMessage, sectionWord) ;
     
           // On recherche les serveurs SMTP.
           std::vector<std::string> MXnames = getMXServer( destinataire, io_service ) ;
     
           // On obtient un socket sur un serveur SMTP.
          boost::asio::ip::tcp::socket socket = getMXSocket( MXnames, io_service ) ;
     
     
          // On envoie l'e-mail.
          sendMail( destinataire, expediteur, message, socket ) ;
    }
    Si seulement j'avais testé cela à l'époque... J'ai honte.
    Sinon, il est possible de réécrire le code plus "proprement" mais bon... j'étais encore "débutant" à l'époque, donc je ne sais pas si on peut vraiment m'en vouloir à ce niveau là.

  8. #8
    Invité régulier
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : novembre 2014
    Messages : 7
    Points : 5
    Points
    5

    Par défaut

    Merci pour les infos supplémentaires et cette réponse rapide Neckara.
    Oui, j'avais corriger certaines petites erreurs pour essayer de compiler le code et envoyer un mail.
    Mais quand je compile, je rencontre directement l'exception renvoyée à cause du throw error dans getMXSocket().
    Je vais essayer de creuser et de voir si je peux réussir moi aussi à envoyer un mail !

    Pur hasard pour ce qui est de mon soudain intérêt par rapport à Matrx63 ^^

  9. #9
    Expert Confirmé Sénior


    Homme Profil pro
    Étudiant
    Inscrit en
    décembre 2011
    Messages
    5 109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 21
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : décembre 2011
    Messages : 5 109
    Points : 15 177
    Points
    15 177

    Par défaut

    As-tu essayé les commandes données à la fin de IV-C-2 ?
    Essaye aussi d'afficher le hostname pour voir s'il est valide.

  10. #10
    Invité régulier
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : novembre 2014
    Messages : 7
    Points : 5
    Points
    5

    Par défaut

    Oui je l'ai essayé en me connectant à un serveur smtp via telnet, ça fonctionne.
    Et le hostname que j'affiche est valide.
    J'obtiens bien une liste de serveur DNS.
    Ça semble surtout coincé lors de la requête DNS envoyé dans askDNS() sur le premier serveur DNS de ma liste.
    Ce premier serveur me renvoie une réponse avec en en-tête ce que j'ai envoyé, mais ensuite il n'y a aucune données particulières (valeurs -51 sur le reste).
    Du coup la fonction getXMServerFromAnswer() qui suit, n'en extrait absolument rien.

  11. #11
    Invité régulier
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : novembre 2014
    Messages : 7
    Points : 5
    Points
    5

    Par défaut

    Bon, maintenant, j'obtiens une réponse plus cohérente des serveur DNS et il n'y a plus d'exceptions.

    J'avais pas vu une petite erreur dans la fonction qui construit la requête DNS : buildDNSQuery().
    A la ligne :
    dnsQueryText += 'x00'; // On n'a pas de réponses.

    Il manquait un anti-slash ( '\x00').
    Mais pas de soucis, tu l'avais bien corrigé dans ton post ! ^^

    Par contre, je suis pas sûr d'avoir bien saisi pourquoi il n'y a pas besoin de s'identifier à son compte mail avant d'envoyer un mail.
    Ça signifierait qu'il est possible d'envoyer un mail à partir de n'importe quelle adresse mail même si ce n'est pas la mienne ? ...

    Grossièrement, qu'est ce qu'il y aurait à modifier si je souhaite me connecter directement au serveur SMTP du domaine de l'expéditeur ?
    Car là, j'ai plus de 2000 serveur MX qui ont été trouvé et le temps de tester la connexion sur chacun est très long.

  12. #12
    Expert Confirmé Sénior


    Homme Profil pro
    Étudiant
    Inscrit en
    décembre 2011
    Messages
    5 109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 21
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : décembre 2011
    Messages : 5 109
    Points : 15 177
    Points
    15 177

    Par défaut

    Ça signifierait qu'il est possible d'envoyer un mail à partir de n'importe quelle adresse mail même si ce n'est pas la mienne ? ...
    Oui.

    Grossièrement, qu'est ce qu'il y aurait à modifier si je souhaite me connecter directement au serveur SMTP du domaine de l'expéditeur ?
    Il faudra faire un startTLS et échanger les paquets en SSL (on va éviter d'envoyer le mot de passe en clair).
    Après, on s'authentifie, il faudrait regarder plus en détail le protocole SMTP (il doit y avoir un lien dans l'article).

    Car là, j'ai plus de 2000 serveur MX qui ont été trouvé et le temps de tester la connexion sur chacun est très long.
    En théorie, tu sors de la boucle dès qu'on réussi à se connecte sur un serveur.
    Après, on peut améliorer le code pour garder un cache des serveur MX associé à un nom de domaine.

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •