2016-12-14 6 views
2

Мне нужно отправить регистрационные коды пользователям с моего сервера. Я разработал для этого некоторый код.Я не могу отправить письмо с gmail

#include <string> 
#include <sstream> 
#include <iostream> 
#include <ctime> 
#include <algorithm> 
#include <random> 
#include <curl/curl.h> 

class EmailAddress 
{ 
public: 
    EmailAddress(const char *email) 
     : email_{email} 
     { 
     } 

    EmailAddress(const std::string &email) 
     : email_{email} 
     { 
     } 

    EmailAddress(const std::string &email, const std::string &displayName) 
     : email_{email.empty() ? "" : "<"+email+">"}, 
      name_{"\"" + displayName + "\""} 
     { 
     } 

    std::string domain() const 
     { 
      return email_.substr(email_.find('@') + 1); 
     } 

    explicit operator const char *() const 
     { 
      return email_.c_str(); 
     } 

    friend std::ostream &operator<<(std::ostream &out, const EmailAddress &email) 
     { 
      return out << email.name_ << " " << email.email_; 
     } 

private: 
    std::string email_; 
    std::string name_; 
}; 

typedef std::vector<EmailAddress> EmailAddresses; 
std::ostream &operator<<(std::ostream &out, const EmailAddresses &emailAddresses); 

class Email 
{ 
public: 
    Email(const EmailAddress &from, 
      const EmailAddress &to, 
      const std::string &subject, 
      const std::string &body, 
      const EmailAddresses &cc = EmailAddresses()) 
     : from_{from} 
     , to_{to} 
     , cc_{cc.empty() ? EmailAddresses(1, to) : cc} 
     , subject_{subject} 
     , body_{body} 
     { 
     } 

    CURLcode send(const std::string &url, 
        const std::string &userName, 
        const std::string &password); 

private: 
    struct StringData { 
      std::string msg; 
      size_t bytesLeft; 
      StringData(std::string &&m) : msg{m}, bytesLeft{msg.size()} {} 
      StringData(std::string &m) = delete; 
     }; 

    static std::string dateTimeNow_(); 
    static size_t payloadSource_(void *ptr, size_t size, size_t nmemb, void *userp); 
    std::string generateMessageId_() const; 
    std::string setPayloadText_(); 

    EmailAddress from_, to_; 
    EmailAddresses cc_; 
    std::string subject_, body_; 
}; 


CURLcode Email::send(const std::string &url, 
        const std::string &userName, 
        const std::string &password) 
{ 
    CURLcode ret = CURLE_OK; 

    struct curl_slist *recipients = NULL; 

    CURL *curl = curl_easy_init(); 

    StringData textData { setPayloadText_() }; 

    if (curl) { 
     std::ostringstream cc; 
     cc << cc_; 

     curl_easy_setopt(curl, CURLOPT_USERNAME,  userName.c_str()); 
     curl_easy_setopt(curl, CURLOPT_PASSWORD,  password.c_str()); 
     curl_easy_setopt(curl, CURLOPT_URL,   url  .c_str()); 

     curl_easy_setopt(curl, CURLOPT_USE_SSL,  (long)CURLUSESSL_ALL); 
     //curl_easy_setopt(curl, CURLOPT_CAINFO,  "/path/to/certificate.pem"); 

     curl_easy_setopt(curl, CURLOPT_MAIL_FROM, (const char *)from_); 
     recipients = curl_slist_append(recipients, (const char *)to_); 
     recipients = curl_slist_append(recipients, cc.str().c_str()); 

     curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); 
     curl_easy_setopt(curl, CURLOPT_READFUNCTION, payloadSource_); 
     curl_easy_setopt(curl, CURLOPT_READDATA,  &textData); 
     curl_easy_setopt(curl, CURLOPT_UPLOAD,  1L); 
     curl_easy_setopt(curl, CURLOPT_VERBOSE,  1L); 

     ret = curl_easy_perform(curl); 

     if (ret != CURLE_OK) { 
      std::cerr << "curl_easy_perform() failed: " 
         << curl_easy_strerror(ret) 
         << std::endl; 
     } 

     curl_slist_free_all(recipients); 
     curl_easy_cleanup(curl); 
    } 

    return ret; 
} 

std::string Email::dateTimeNow_() 
{ 
    const int RFC5322_TIME_LEN = 32; 

    std::string ret; 
    ret.resize(RFC5322_TIME_LEN); 

    time_t tt; 

#ifdef _MSC_VER 
    time(&tt); 
    tm *t = localtime(&tt); 
#else 
    tm tv, *t = &tv; 
    tt = time(&tt); 
    localtime_r(&tt, t); 
#endif 

    strftime(&ret[0], RFC5322_TIME_LEN, "%a, %d %b %Y %H:%M:%S %z", t); 

    return ret; 
} 

inline std::string Email::generateMessageId_() const 
{ 
    const size_t MESSAGE_ID_LEN = 37; 

    tm t; 
    time_t tt; 
    time(&tt); 

#ifdef _MSC_VER 
    gmtime_s(&t, &tt); 
#else 
    gmtime_r(&tt, &t); 
#endif 

    std::string ret; 
    ret.resize(MESSAGE_ID_LEN); 
    size_t dateLen = std::strftime(&ret[0], MESSAGE_ID_LEN, "%Y%m%d%H%M%S", &t); 

    static const std::string alphaNum { 
     "" 
     "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
     "abcdefghijklmnopqrstuvwxyz" }; 

    std::mt19937 gen; 
    std::uniform_int_distribution<> distr(0, alphaNum.length() - 1); 

    std::generate_n(ret.begin() + dateLen, 
        MESSAGE_ID_LEN - dateLen, 
        [&]() { return alphaNum[distr(gen)]; }); 

    return ret; 
} 

size_t Email::payloadSource_(void *ptr, size_t size, size_t nmemb, void *userp) 
{ 
    StringData *text = reinterpret_cast<StringData *>(userp); 

    if ((size == 0) || (nmemb == 0) || ((size * nmemb) < 1) || (text->bytesLeft == 0)) { 
     return 0; 
    } 

    if ((nmemb * size) >= text->msg.size()) { 
     text->bytesLeft = 0; 
     return text->msg.copy(reinterpret_cast<char *>(ptr), text->msg.size()); 
    } 

    return 0; 
} 

std::string Email::setPayloadText_() 
{ 
    std::string ret = "Date: " + dateTimeNow_() + "\r\n"; 

    std::ostringstream oss; 
    oss << "To: " << to_ << "\r\n" 
      "From: " << from_ << "\r\n"; 

    if (cc_.size() > 1) { 
     oss << "Cc: " << cc_ << "\r\n"; 
    } 

    ret += oss.str(); 

    ret += 
     "Message-ID: <" + generateMessageId_() + "@" + from_.domain() + ">\r\n" 
     "Subject: " + subject_ + "\r\n" 
     "\r\n" + 
     body_ + "\r\n" 
     "\r\n"; 

    return ret; 
} 

std::ostream &operator<<(std::ostream &out, const EmailAddresses &emailAddresses) 
{ 
    if (!emailAddresses.empty()) { 
     auto it = emailAddresses.begin(); 
     out << *it; 
     while (++it != emailAddresses.end()) { 
      out << "," << *it; 
     } 
    } 

    return out; 
} 

Если я использую почтовый сервис для отправки электронной почты, он работает хорошо. Но если я использую gmail.com службы я получаю сообщение об ошибке:

  • Rebuilt URL to: smtp://smtp.gmail.com:465/
  • Trying 64.233.165.109...
  • Connected to smtp.gmail.com (64.233.165.109) port 465 (#0)
  • response reading failed
  • Closing connection 0 curl_easy_perform() failed: Failure when receiving data from the peer
Email email({ "[email protected]", "Name" }, 
       "[email protected]", 
       "Subj", 
       "Body"); 

email.send( "smtp://smtp.gmail.com:465", 
       "[email protected]", 
       "Password"); 

Что я сделал не так?

+0

ли вы ваш ретранслятор SMTP включен для Gmail? – TheValyreanGroup

+1

У вас есть пароль для приложения? Вы не можете использовать свой обычный пароль, потому что безопасность. –

+1

В прошлый раз, когда я это делал, мне пришлось отказаться от внутренней безопасности G-mail (и они изменили, как это сделать недавно, поэтому я не могу дать хороший ответ), и, как предлагает @ Raindrop7, пришлось включить компиляцию в Поддержка SSL. Использовал OpenSSL, но должен был сделать хакерство сценариев сборки по умолчанию, чтобы cURL и OpenSSL играли хорошо в Windows с mingw. – user4581301

ответ

2

Я думаю, что вы пропустили проверку подлинности сервера Gmail, вот некоторые настройки для исходящей почты:

исходящей почты (SMTP)

smtp.gmail.com 
Requires SSL: Yes 
Requires TLS: Yes (if available) 
Requires Authentication: Yes 
Port for SSL: 465 
Port for TLS/STARTTLS: 587 

также перейти в свой аккаунт и включить IMAP и POP и сохранить изменения.

+0

Для 587: curl_easy_perform() не удалось: Ошибка отправки данных сверстнику – Ufx

+0

@Ufx cURL выплевывает, или могут быть сконфигурированы для выплескивания, некоторые довольно подробные диагностики. какую среду разработки и ОС вы используете? – user4581301

+0

@ user4581301 сейчас я использую VS 2015 и Windows 7 – Ufx

0

вы можете использовать эту библиотеку для отправки почты: http://sourceforge.net/projects/libquickmail/

+0

Можете ли вы мне помочь? https://stackoverflow.com/questions/41322794/i-get-error-when-im-trying-to-send-email-using-libquickmail – Ufx