[C++] Jak wysłać e-mail?

mto9

Użytkownik
Dołączył
Kwiecień 20, 2011
Posty
81
Już gdzieś na forum wklejałem ten kod, ale udostępnię go jeszcze raz. Jest to prosta w obsłudze, zapewniająca podstawowe funkcję "ala" biblioteka umożliwiająca wysyłanie e-maili z załącznikami.

Kod składa się z dwóch klas:
- Message reprezentuje wiadomość e-mail którą można wykorzystać wiele razy
- SMTPTransport odpowiedzialna za wysyłanie wiadomości

Message.h
Kod:
#ifndef MESSAGE_H
#define MESSAGE_H

#include <string>
#include <vector>

class Message
{
public:
    Message(const std::string & subject = std::string(), const std::string & contents = std::string(),
            std::vector<std::string> recipients = std::vector<std::string>(),
            std::vector<std::string> attachments = std::vector<std::string>());

    bool        addAttachment(const std::string & filePath);
    void        addAttachments(std::vector<std::string> & v);
    bool        addRecipient(const std::string & e_mailAddress);
    void        addRecipients(std::vector<std::string> & v);
    void        clear();
    int         findAttachment(const std::string & filePath) const;
    int         findRecipient(const std::string & e_mailAddress) const;
    std::vector<std::string> getAllAttachments() const { return attachments; }
    std::vector<std::string> getAllRecipients() const { return recipients; }
    std::string getContents() const { return contents; }
    std::string getAttachmentAt(int index) const;
    std::string getRecipientAt(int index) const;
    int         getAttachmentCount() const { return attachments.size(); }
    int         getRecipientCount() const { return recipients.size(); }
    std::string getSubject() const { return subject; }
    bool        isReadyToSend() const;
    bool        removeAttachmentAt(int index);
    bool        removeRecipientAt(int index);
    void        removeAllAttachments() { attachments.clear(); }
    void        removeAllRecipients() { recipients.clear(); }
    void        setContents(const std::string & newContents) { contents = newContents; }
    void        setSubject(const std::string & newSubject) { subject = newSubject; }


private:
    bool        fileExists(const std::string & filePath) const;
    bool        isAlreadyUsed(const std::string & name,std::vector<std::string> & v) const;

    std::vector<std::string> attachments;
    std::string contents;
    std::vector<std::string> recipients;
    std::string subject;

};

#endif // MESSAGE_H

Message.cpp
Kod:
#include "message.h"
#include <fstream>
//#include <regex>

Message::Message(const std::string & subject, const std::string & contents,
                 std::vector<std::string> recipients, std::vector<std::string> attachments):
    subject(subject),
    contents(contents),
    recipients(recipients),
    attachments(attachments)
{

}

bool Message::addAttachment(const std::string &filePath)
{
    if((!isAlreadyUsed(filePath, attachments)) && fileExists(filePath))
    {
        this->attachments.push_back(filePath);
        return true;
    }
    else return false;
}

void Message::addAttachments(std::vector<std::string> &v)
{
    for(int i=0; i<v.size(); i++) this->addAttachment(v[i]);
}

bool Message::addRecipient(const std::string &e_mailAddress)
{
    /* // Version for C++0x //

    std::regex model("^[-!#$%&'*+/0-9=?A-Z^_a-z{|}~](\.?[-!#$%&'*+/0-9=?A-Z^_a-z{|}~])*@"
                     "[a-zA-Z](-?[a-zA-Z0-9])*(\.[a-zA-Z](-?[a-zA-Z0-9])*)+$");
    if(std::regex_match(e_mailAddress, model) && (!isAlreadyUsed(e_mailAddress, recipients)))
    {
        this->recipients.push_back(e_mailAddress);
        return true;
    }
    else return false;

    */

    this->recipients.push_back(e_mailAddress);
    return true;
}

void Message::addRecipients(std::vector<std::string> &v)
{
    for(int i=0; i<v.size(); i++) this->addRecipient(v[i]);
}

void Message::clear()
{
    this->subject = std::string();
    this->contents = std::string();
    this->recipients.clear();
    this->attachments.clear();
}

int Message::findRecipient(const std::string &e_mailAddress) const
{
    for(int i=0; i<recipients.size(); i++) if(e_mailAddress == recipients[i]) return i;
    return -1;
}

std::string Message::getAttachmentAt(int index) const
{
    if(this->attachments.size() > index) return attachments[index];
    else return std::string();
}

int Message::findAttachment(const std::string &filePath) const
{
    for(int i=0; i<attachments.size(); i++) if(filePath == attachments[i]) return i;
    return -1;
}

std::string Message::getRecipientAt(int index) const
{
    if(this->recipients.size() > index) return this->recipients[index];
    else return std::string();
}

bool Message::isReadyToSend() const
{
    if((!this->subject.empty()) && (!this->contents.empty()) && this->recipients.size() > 0) return true;
    else return false;
}

bool Message::removeAttachmentAt(int index)
{
    if(this->attachments.size() > index)
    {
        this->attachments.erase(attachments.begin() + index);
        return true;
    }
    else return false;
}

bool Message::removeRecipientAt(int index)
{
    if(this->recipients.size() > index)
    {
        this->recipients.erase(recipients.begin() + index);
        return true;
    }
    else return false;
}

bool Message::fileExists(const std::string &filePath) const
{
    std::ifstream file;
    file.open(filePath.c_str());
    if(file.is_open())
    {
        file.close();
        return true;
    }
    else return false;
}

bool Message::isAlreadyUsed(const std::string & name, std::vector<std::string> & v) const
{
    for(int i=0; i<v.size(); i++) if(name == v[i]) return true;
    return false;
}

SMTPTransoprt.h
Kod:
#ifndef SMTPTRANSPORT_H
#define SMTPTRANSPORT_H

#include "message.h"

class SMTPTransport
{
public:
    //enum Encryption {Lack, SSL, TLS};

    SMTPTransport(const std::string & senderAddress = std::string(),
                  const std::string & senderPassword = std::string(),
                  const std::string & hostAddress = std::string(),
                  unsigned port = 465/*, Encryption encryption = SSL*/);

    //Encryption  getEncryption() const { return encryption; }
    std::string getHostAddress() const { return hostAddress; }
    std::string getLastError() const { return lastError; }
    unsigned    getPort() const { return port; }
    std::string getSenderAddress() const { return senderAddress; }
    std::string getSenderPassword() const { return senderPassword; }
    bool        isConfigured() const;
    bool        send(Message & message);
    //void        setEncryption(Encryption newEncryption) { encryption = newEncryption; }
    void        setHostAddress(const std::string & newHostAddress) { hostAddress = newHostAddress; }
    void        setPort(unsigned newPort) { port = newPort; }
    bool        setSenderAddress(const std::string & e_mailAddress);
    void        setSenderPassword(const std::string & password) { senderPassword = password; }

private:
    std::string getFileName(const std::string & file) const { return file.substr(file.rfind('\\')+1); }
    std::string getMIMEType(const std::string & file) const;
    std::string readFile(const std::string & filePath) const;
    std::string toBase64(const std::string & stringToEncode) const;

    //Encryption  encryption;
    std::string hostAddress;
    mutable std::string lastError;
    unsigned    port;
    std::string senderAddress;
    std::string senderPassword;

};

#endif // SMTPTRANSPORT_H

SMTPTransport.cpp
Kod:
#include "smtptransport.h"
#include <fstream>
//#include <regex>
#include <sstream>
#include <streambuf>
#include <WinSock2.h>

SMTPTransport::SMTPTransport(const std::string & senderAddress, const std::string & senderPassword,
                             const std::string & hostAddress, unsigned port/*, Encryption encryption*/):
    senderPassword(senderPassword),
    hostAddress(hostAddress),
    port(port)/*,
    encryption(encryption)*/
{
    setSenderAddress(senderAddress);
}

inline bool SMTPTransport::isConfigured() const
{
    return (!(this->senderAddress.empty()) && !(this->senderPassword.empty()) && !(this->hostAddress.empty()));
}

bool SMTPTransport::send(Message &message)
{
    if(!message.isReadyToSend())
    {
        this->lastError = "Message is not ready to send";
        return false;
    }
    if(!(this->isConfigured()))
    {
        this->lastError = "SMTPTransport is not configured";
        return false;
    }

    WSADATA wsaData;
    WSAStartup(MAKEWORD(2,2), &wsaData);

    LPHOSTENT hostEntry = gethostbyname(this->hostAddress.c_str());
    if(hostEntry == 0)
    {
        this->lastError = "gethostbyname returns a null pointer";
        WSACleanup();
        return false;
    }
    SOCKADDR_IN saddr;
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    const unsigned sizeBuffer = 1024;
    char buffer[sizeBuffer];
    std::string tempString, tempString2;

    saddr.sin_addr = *((LPIN_ADDR)*hostEntry->h_addr_list);
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(this->port);

    if(connect(sock, (sockaddr*)&saddr, sizeof(sockaddr)) == SOCKET_ERROR)
    {
        this->lastError = "SOCKET_ERROR";
        WSACleanup();
        return false;
    }

    recv(sock, buffer, sizeBuffer - 1, 0);
    if(buffer[0] == '5' || buffer[0] == '4')
    {
        this->lastError = buffer;
        closesocket(sock);
        WSACleanup();
        return false;
    }

    tempString = "EHLO " + this->hostAddress + "\r\n";
    ::send(sock, tempString.c_str(), tempString.size(), 0);
    recv(sock, buffer, sizeBuffer - 1, 0);
    if(buffer[0] == '5' || buffer[0] == '4')
    {
        this->lastError = buffer;
        closesocket(sock);
        WSACleanup();
        return false;
    }

    ::send(sock, "AUTH LOGIN\r\n", 12, 0);
    recv(sock, buffer, sizeBuffer - 1, 0);
    if(buffer[0] == '5' || buffer[0] == '4')
    {
        this->lastError = buffer;
        closesocket(sock);
        WSACleanup();
        return false;
    }

    tempString = this->toBase64(this->senderAddress) + "\r\n";
    ::send(sock, tempString.c_str(), tempString.size(), 0);
    recv(sock, buffer, sizeBuffer - 1, 0);
    if(buffer[0] == '5' || buffer[0] == '4')
    {
        this->lastError = buffer;
        closesocket(sock);
        WSACleanup();
        return false;
    }

    tempString = this->toBase64(this->senderPassword) + "\r\n";
    ::send(sock, tempString.c_str(), tempString.size(), 0);
    recv(sock, buffer, sizeBuffer - 1, 0);
    if(buffer[0] == '5' || buffer[0] == '4')
    {
        this->lastError = buffer;
        closesocket(sock);
        WSACleanup();
        return false;
    }

    tempString = "MAIL FROM: <" + this->senderAddress + ">\r\n";
    ::send(sock, tempString.c_str(), tempString.size(), 0);
    recv(sock, buffer, sizeBuffer - 1, 0);
    if(buffer[0] == '5' || buffer[0] == '4')
    {
        this->lastError = buffer;
        closesocket(sock);
        WSACleanup();
        return false;
    }

    for(int i=0; i<message.getRecipientCount(); i++)
    {
        tempString = "RCPT TO: <" + message.getRecipientAt(i) + ">\r\n";
        tempString2 += (message.getRecipientAt(i) + ", ");
        ::send(sock, tempString.c_str(), tempString.size(), 0);
        recv(sock, buffer, sizeBuffer - 1, 0);
        if(buffer[0] == '5' || buffer[0] == '4')
        {
            this->lastError = buffer;
            closesocket(sock);
            WSACleanup();
            return false;
        }
    }

    ::send(sock, "DATA\r\n", 6, 0);
    recv(sock, buffer, sizeBuffer - 1, 0);
    if(buffer[0] == '5' || buffer[0] == '4')
    {
        this->lastError = buffer;
        closesocket(sock);
        WSACleanup();
        return false;
    }

    ::send(sock, "MIME-Version: 1.0\r\n", 19, 0);

    tempString = "Subject: =?Windows-1250?B?" + this->toBase64(message.getSubject()) + "?=\r\n";
    ::send(sock, tempString.c_str(), tempString.size(), 0);

    tempString = "From: " + this->senderAddress + "\r\n";
    ::send(sock, tempString.c_str(), tempString.size(), 0);

    tempString = "To: " + tempString2 + "\r\n";
    ::send(sock, tempString.c_str(), tempString.size(), 0);

    if(message.getAttachmentCount() > 0)
    {
        ::send(sock, "Content-Type: multipart/mixed; boundary=00newline9\r\n\r\n", 54, 0);
        ::send(sock, "--00newline9\r\n", 14, 0);
    }

    ::send(sock, "Content-Type: text/plain; charset=Windows-1250\r\n", 48, 0);
    ::send(sock, "Content-Transfer-Encoding: base64\r\n\r\n", 37, 0);

    tempString = this->toBase64(message.getContents()) + "\r\n\r\n";
    ::send(sock, tempString.c_str(), tempString.size(), 0);

    if(message.getAttachmentCount() > 0)
    {
        for(int i=0; i<message.getAttachmentCount(); i++)
        {
            ::send(sock, "--00newline9\r\n", 14, 0);

            tempString = "Content-Type: " + this->getMIMEType(message.getAttachmentAt(i)) +
                         "; name=\"" + this->getFileName(message.getAttachmentAt(i)) + "\"\r\n";
            ::send(sock, tempString.c_str(), tempString.size(), 0);

            tempString = "Content-Disposition: attachment; filename=\"" + getFileName(message.getAttachmentAt(i)) + "\"\r\n";
            ::send(sock, tempString.c_str(), tempString.size(), 0);

            ::send(sock, "Content-Transfer-Encoding: base64\r\n\r\n", 37, 0);

            tempString = this->toBase64(this->readFile(message.getAttachmentAt(i))) + "\r\n";
            ::send(sock, tempString.c_str(), tempString.size(), 0);
        }

        ::send(sock, "--00newline9--\r\n", 16, 0);
    }

    ::send(sock, ".\r\n", 3, 0);
    recv(sock, buffer, sizeBuffer - 1, 0);
    if(buffer[0] == '5' || buffer[0] == '4')
    {
        this->lastError = buffer;
        closesocket(sock);
        WSACleanup();
        return false;
    }

    ::send(sock, "QUIT\r\n", 6, 0);
    recv(sock, buffer, sizeBuffer - 1, 0);

    closesocket(sock);
    WSACleanup();
    return true;
}

bool SMTPTransport::setSenderAddress(const std::string &e_mailAddress)
{
    /* // Version for C++0x //

    std::regex model("^[-!#$%&'*+/0-9=?A-Z^_a-z{|}~](\.?[-!#$%&'*+/0-9=?A-Z^_a-z{|}~])*@"
                     "[a-zA-Z](-?[a-zA-Z0-9])*(\.[a-zA-Z](-?[a-zA-Z0-9])*)+$");
    if(std::regex_match(e_mailAddress, model))
    {
        this->senderAddress = e_mailAddress;
        return true;
    }
    else return false;

    */

    this->senderAddress = e_mailAddress;
    return true;
}

std::string SMTPTransport::getMIMEType(const std::string &file) const
{
    std::string enlargement = file.substr(file.rfind('.')+1);

    /*  The most popular types of files */
    if(enlargement=="zip")  return "application/zip";
    if(enlargement=="rar")  return "application/rar";
    if(enlargement=="mp3")  return "audio/mpeg";
    if(enlargement=="pdf")  return "application/pdf";
    if(enlargement=="html") return "text/html";
    if(enlargement=="htm")  return "text/html";
    if(enlargement=="png")  return "image/png";
    if(enlargement=="gif")  return "image/gif";
    if(enlargement=="bmp")  return "image/bmp";
    if(enlargement=="jpeg") return "image/jpeg";
    if(enlargement=="jpg")  return "image/jpeg";
    if(enlargement=="pps")  return "application/vnd.ms-powerpoint";
    if(enlargement=="ppt")  return "application/vnd.ms-powerpoint";
    if(enlargement=="pptx") return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
    if(enlargement=="xls")  return "application/vnd.ms-excel";
    if(enlargement=="xlsx") return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    if(enlargement=="txt")  return "text/plain";
    if(enlargement=="doc")  return "application/msword";
    if(enlargement=="docx") return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
    if(enlargement=="avi")  return "video/x-msvideo";
    if(enlargement=="mov")  return "video/quicktime";
    if(enlargement=="wmv")  return "video/x-ms-wmv";
    if(enlargement=="mpeg") return "video/mpeg";
    if(enlargement=="mpg")  return "video/mpeg";
    if(enlargement=="wma")  return "audio/x-ms-wma";
    /*  Graphic files */
    if(enlargement=="jpe")  return "image/jpeg";
    if(enlargement=="ico")  return "image/x-icon";
    if(enlargement=="psd")  return "application/photoshop";
    if(enlargement=="tif")  return "image/tiff";
    if(enlargement=="tiff") return "image/tiff";
    if(enlargement=="xpm")  return "image/x-xpixmap";
    if(enlargement=="svg")  return "image/svg+xml";
    if(enlargement=="swf")  return "application/x-shockwave-flash";
    if(enlargement=="eps")  return "application/postscript";
    /*  Audio files */
    if(enlargement=="ra")   return "audio/x-realaudio";
    if(enlargement=="rm")   return "audio/x-pn-realaudio";
    if(enlargement=="ram")  return "audio/x-pn-realaudio";
    if(enlargement=="wav")  return "audio/x-wav";
    if(enlargement=="mid")  return "audio/midi";
    if(enlargement=="midi") return "audio/midi";
    if(enlargement=="aif")  return "audio/x-aiff";
    if(enlargement=="aiff") return "audio/x-aiff";
    if(enlargement=="aifc") return "audio/x-aiff";
    if(enlargement=="mp2")  return "audio/mpeg";
    /*  Video files */
    if(enlargement=="mp4")  return "video/mp4";
    if(enlargement=="mpe")  return "video/mpeg";
    if(enlargement=="ogv")  return "video/ogg";
    if(enlargement=="qt")   return "video/quicktime";
    if(enlargement=="asf")  return "video/x-ms-asf";
    /*  Text documents */
    if(enlargement=="odt")  return "application/vnd.oasis.opendocument.text";
    if(enlargement=="ott")  return "application/vnd.oasis.opendocument.text-template";
    if(enlargement=="pages")return "application/x-iwork-pages-sffpages";
    if(enlargement=="rtf")  return "application/rtf";
    if(enlargement=="sxw")  return "application/vnd.sun.xml.writer";
    /*  Spreadsheets */
    if(enlargement=="csv")  return "text/csv";
    if(enlargement=="ods")  return "application/vnd.oasis.opendocument.spreadsheet";
    if(enlargement=="ots")  return "application/vnd.oasis.opendocument.spreadsheet-template";
    if(enlargement=="sxc")  return "application/vnd.sun.xml.calc";
    /*  Multimedia presentations */
    if(enlargement=="ppsx") return "application/vnd.openxmlformats-officedocument.presentationml.slideshow";
    if(enlargement=="odp")  return "application/vnd.oasis.opendocument.presentation";
    if(enlargement=="otp")  return "application/vnd.oasis.opendocument.presentation-template";
    if(enlargement=="sxi")  return "application/vnd.sun.xml.impress";
    /*  Archives */
    if(enlargement=="tar")  return "application/x-tar";
    if(enlargement=="tgz")  return "application/x-gzip";
    /*  Other */
    if(enlargement=="xml")  return "text/xml";
    if(enlargement=="php")  return "application/x-httpd-php";
    if(enlargement=="cpp")  return "text/x-c++src";
    if(enlargement=="c")    return "text/x-csrc";
    if(enlargement=="js")   return "application/x-javascript";

    return "application/octet-stream";
}

std::string SMTPTransport::readFile(const std::string &filePath) const
{
    std::ifstream file(filePath.c_str(), std::ios::binary);
    std::stringstream buffer;
    buffer << file.rdbuf();
    return buffer.str();
}

std::string SMTPTransport::toBase64(const std::string &stringToEncode) const
{
    static const std::string base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
            "abcdefghijklmnopqrstuvwxyz"
            "0123456789+/";

    std::string result;
    unsigned size = stringToEncode.size();
    int i=0, j=0, index=0;
    unsigned char charArrary3[3];
    unsigned char charArrary4[4];

    while(size--)
    {
        charArrary3[i++] = stringToEncode[index++];
        if(i == 3)
        {
            charArrary4[0] = (charArrary3[0] & 0xfc) >> 2;
            charArrary4[1] = ((charArrary3[0] & 0x03) << 4) + ((charArrary3[1] & 0xf0) >> 4);
            charArrary4[2] = ((charArrary3[1] & 0x0f) << 2) + ((charArrary3[2] & 0xc0) >> 6);
            charArrary4[3] = charArrary3[2] & 0x3f;

            for(i=0; i<4; i++) result += base64Chars[charArrary4[i]];
            i = 0;
        }
    }

    if(i)
    {
        for(j=i; j<3; j++) charArrary3[j] = '\0';
        charArrary4[0] = (charArrary3[0] & 0xfc) >> 2;
        charArrary4[1] = ((charArrary3[0] & 0x03) << 4) + ((charArrary3[1] & 0xf0) >> 4);
        charArrary4[2] = ((charArrary3[1] & 0x0f) << 2) + ((charArrary3[2] & 0xc0) >> 6);
        charArrary4[3] = charArrary3[2] & 0x3f;

        for(j=0; j<i+1; j++) result += base64Chars[charArrary4[j]];

        while(i++ < 3) result += '=';
    }

    return result;
}

Sposób użycia:
Kod:
    Message message;
    message.setSubject("temat");
    message.setContents("tresc");
    message.addAttachment("C:\\plik.txt");
    message.addRecipient("[email protected]");

    SMTPTransport smtp;
    smtp.setHostAddress("poczta.interia.pl");
    smtp.setPort(587);
    smtp.setSenderAddress("[email protected]");
    smtp.setSenderPassword("997");
    smtp.send(message)
 
Ostatnia edycja:
Do góry Bottom