#ifndef ____smtpsend_h__ # define ____smtpsend_h__ # include "Tag.h" # include "ZString.h" # include "MString.h" # include # include namespace jet { /// /// /// /// One-shot authenticated SMTP submission to BARANTMAIL's own /// implicit-TLS submission port (config key "smtpPort" - matches /// barantmail.cfg's smtpTLS.port, :465, the same implicit-TLS style /// as IMAP's :993 - no STARTTLS negotiation). Connects, TLS- /// handshakes, AUTH LOGIN with the SAME mailbox credentials already /// used by (so the message goes out authenticated as the /// actual connected mailbox, not the site's own transactional-mail /// identity - see barant.tag's separate tag for that), then /// MAIL FROM/RCPT TO/DATAs a freshly-built RFC 5322 message /// (Date/From/To/Subject/MIME headers, HTML body), then QUITs. The /// authenticated user IS the From address - SMTP submission /// requires MAIL FROM to match the authenticated identity anyway, so /// there's no separate "from" keyword. /// /// No connection pooling, unlike __imap - composing mail is rare /// enough that a fresh connect/auth/send/close per message is fine. /// /// Throws coreutils::Exception (401 for a bad login, 502 for any /// other connect/protocol/rejected-recipient failure) on any /// failure - same convention as __imap. /// class __smtpsend : public Tag { public: __smtpsend(coreutils::ZString &in, coreutils::MString &parentOut, Global &global, Tag *parent, Tag *local); private: SSL_CTX *ctx = nullptr; SSL *ssl = nullptr; int fd = -1; std::string recvBuffer; size_t recvPos = 0; void sendLine(const std::string &line); char readByte(); std::string readLine(); // Reads one (possibly multi-line, "250-text"/"250 text" // continuation-marked) SMTP reply and returns its 3-digit code; // throws if the code's first digit doesn't match expectedCode's. int readReply(int expectedCode); void closeConnection(); static std::string base64Encode(const std::string &s); static std::string rfc2822Date(); // Builds the full RFC 5322 message (headers + dot-stuffed body) // handed to SMTP's DATA command. static std::string buildMessage(const std::string &from, const std::string &to, const std::string &subject, const std::string &html); }; } #endif