title: I can't send email from gmail
body: <p>I need to send registration codes to users from my server. I developed some code for this.</p>
  
  <pre><code>#include &lt;string&gt;
  #include &lt;sstream&gt;
  #include &lt;iostream&gt;
  #include &lt;ctime&gt;
  #include &lt;algorithm&gt;
  #include &lt;random&gt;
  #include &lt;curl/curl.h&gt;
  
  class EmailAddress 
  {
  public:
      EmailAddress(const char *email)
          : email_{email}
          {
          }
  
      EmailAddress(const std::string &amp;email)
          : email_{email}
          {
          }
  
      EmailAddress(const std::string &amp;email, const std::string &amp;displayName)
          : email_{email.empty() ? "" : "&lt;"+email+"&gt;"},
            name_{"\"" + displayName + "\""}
          {
          }
  
      std::string domain() const
          {
              return email_.substr(email_.find('@') + 1);
          }
  
      explicit operator const char *() const
          {
              return email_.c_str();
          }
  
      friend std::ostream &amp;operator&lt;&lt;(std::ostream &amp;out, const EmailAddress &amp;email)
          {
              return out &lt;&lt; email.name_ &lt;&lt; " " &lt;&lt; email.email_;
          }
  
  private:
      std::string email_;
      std::string name_;
  };
  
  typedef std::vector&lt;EmailAddress&gt; EmailAddresses;
  std::ostream &amp;operator&lt;&lt;(std::ostream &amp;out, const EmailAddresses &amp;emailAddresses);
  
  class Email
  {
  public:
      Email(const EmailAddress   &amp;from,
            const EmailAddress   &amp;to,
            const std::string    &amp;subject,
            const std::string    &amp;body,
            const EmailAddresses &amp;cc = EmailAddresses())
          : from_{from}
          , to_{to}
          , cc_{cc.empty() ? EmailAddresses(1, to) : cc}
          , subject_{subject}
          , body_{body}
          {
          }
  
      CURLcode send(const std::string &amp;url,
                    const std::string &amp;userName, 
                    const std::string &amp;password);
  
  private:
      struct StringData {
              std::string msg;
              size_t bytesLeft;
              StringData(std::string &amp;&amp;m) : msg{m}, bytesLeft{msg.size()} {}
              StringData(std::string  &amp;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 &amp;url,
                       const std::string &amp;userName,
                       const std::string &amp;password)
  {
      CURLcode ret = CURLE_OK;
  
      struct curl_slist *recipients = NULL;
  
      CURL *curl = curl_easy_init();
  
      StringData textData { setPayloadText_() };
  
      if (curl) {
          std::ostringstream cc;
          cc &lt;&lt; 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,     &amp;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 &lt;&lt; "curl_easy_perform() failed: "
                        &lt;&lt; curl_easy_strerror(ret)
                        &lt;&lt; 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(&amp;tt);
      tm *t = localtime(&amp;tt);
  #else
      tm tv, *t = &amp;tv;
      tt = time(&amp;tt);
      localtime_r(&amp;tt, t);
  #endif
  
      strftime(&amp;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(&amp;tt);
  
  #ifdef _MSC_VER
      gmtime_s(&amp;t, &amp;tt);
  #else
      gmtime_r(&amp;tt, &amp;t);
  #endif
  
      std::string ret;
      ret.resize(MESSAGE_ID_LEN);
      size_t dateLen = std::strftime(&amp;ret[0], MESSAGE_ID_LEN, "%Y%m%d%H%M%S", &amp;t);
  
      static const std::string alphaNum {
          "0123456789"
          "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
          "abcdefghijklmnopqrstuvwxyz" };
  
      std::mt19937 gen;
      std::uniform_int_distribution&lt;&gt; distr(0, alphaNum.length() - 1);
  
      std::generate_n(ret.begin() + dateLen,
                      MESSAGE_ID_LEN - dateLen,
                      [&amp;]() { return alphaNum[distr(gen)]; });
  
      return ret;
  }
  
  size_t Email::payloadSource_(void *ptr, size_t size, size_t nmemb, void *userp)
  {
      StringData *text = reinterpret_cast&lt;StringData *&gt;(userp);
  
      if ((size == 0) || (nmemb == 0) || ((size * nmemb) &lt; 1) || (text-&gt;bytesLeft == 0)) {
          return 0;
      }
  
      if ((nmemb * size) &gt;= text-&gt;msg.size()) {
          text-&gt;bytesLeft = 0;
          return text-&gt;msg.copy(reinterpret_cast&lt;char *&gt;(ptr), text-&gt;msg.size());
      }
  
      return 0;
  }
  
  std::string Email::setPayloadText_()
  {
      std::string ret = "Date: " + dateTimeNow_() + "\r\n";
  
      std::ostringstream oss;
      oss &lt;&lt; "To: "   &lt;&lt; to_   &lt;&lt; "\r\n"
             "From: " &lt;&lt; from_ &lt;&lt; "\r\n";
  
      if (cc_.size() &gt; 1) {
          oss &lt;&lt;   "Cc: "   &lt;&lt; cc_   &lt;&lt; "\r\n";
      }
  
      ret += oss.str();
  
      ret +=
          "Message-ID: &lt;" + generateMessageId_() + "@" + from_.domain() + "&gt;\r\n"
          "Subject: " + subject_ + "\r\n"
          "\r\n" +
          body_ + "\r\n"
          "\r\n";
  
      return ret;
  }
  
  std::ostream &amp;operator&lt;&lt;(std::ostream &amp;out, const EmailAddresses &amp;emailAddresses)
  {
      if (!emailAddresses.empty()) {
          auto it = emailAddresses.begin();
          out &lt;&lt; *it;
          while (++it != emailAddresses.end()) {
              out &lt;&lt; "," &lt;&lt; *it;
          }
      }
  
      return out;
  }
  </code></pre>
  
  <p>If I use mail.ru service for sending email it works good. But if I use gmail.com  service I get an error:</p>
  
  <blockquote>
    <ul>
    <li>Rebuilt URL to: smtp://smtp.gmail.com:465/</li>
    <li>Trying 64.233.165.109...</li>
    <li>Connected to smtp.gmail.com (64.233.165.109) port 465 (#0)</li>
    <li>response reading failed</li>
    <li>Closing connection 0
    curl_easy_perform() failed: Failure when receiving data from the peer</li>
    </ul>
  </blockquote>
  
  <pre><code>Email email({ "...@gmail.com", "Name" },
                "...@gmail.com",
                "Subj",
                "Body");
  
  email.send(   "smtp://smtp.gmail.com:465",
                "...@gmail.com",
                "Password");
  </code></pre>
  
  <p>What did I do wrong?</p>