// // File: hzMailer.h // // Legal Notice: This file is part of the HadronZoo C++ Class Library. // // Copyright 2025 HadronZoo Project (http://www.hadronzoo.com) // // The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free // Software Foundation, either version 3 of the License, or any later version. // // The HadronZoo C++ Class Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR // A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses. //
// // Prototypes for the HadronZoo email facilities //
#ifndef hzMailer_h #define hzMailer_h
#include "hzMimetype.h" #include "hzIpaddr.h" #include "hzEmaddr.h" #include "hzTmplList.h" #include "hzTmplVect.h" #include "hzTmplSet.h" #include "hzTmplMapS.h"
enum SMTPCode { // Category: Internet // // All possible SMTP return codes
SMTP_NOOP = 0, // Returned by GetSMTPCode() in error
// Initial Connection Errors SMTP_CONN_FAIL = 101, // The server is unable to connect SMTP_CONN_REFUSED = 111, // Connection refused or inability to open an SMTP stream
// Success SMTP_STATUS_NS = 200, // Non standard system status message or help reply SMTP_STATUS = 211, // System status, or system help reply SMTP_HELP = 214, // Help message (this reply is useful only to the human user) SMTP_READY = 220, // Service ready SMTP_QUIT = 221, // Service closing transmission channel SMTP_GO_AHEAD = 235, // Tells client to go ahead SMTP_OK = 250, // Requested mail action okay, completed SMTP_NOTLOCAL = 251, // User not local; will forward to SMTP_NOVRFY = 252, // Cannot VRFY user, but will accept message and attempt delivery
// Directives to send SMTP_LOGINFO = 334, // Login info, either username or password SMTP_SENDDATA = 354, // Start mail input; end with <CRLF>.<CRLF>
// Temporary Errors SMTP_TIMEOUT = 420, // General connection timeout issue SMTP_UNAVAILABLE = 421, // Service not available, SMTP_MBOX_FULL = 422, // The recipients mailbox has exceeded its storage limit SMTP_DISK_FULL = 431, // Not enough space on the disk - Expected to be temporary. SMTP_MBOX_HALT = 432, // Recipients incoming mail queue has been stopped SMTP_TIMEOUT_PX = 441, // The recipients server is not responding SMTP_CONN_XMIT = 442, // The connection was dropped during the transmission. SMTP_CONN_HOPS = 446, // The maximum hop count was exceeded for the message SMTP_TIMEOUT_NS = 447, // Non standard timeout: Some SMTP servers will send this if they have decided to time out the client (for being too slow). SMTP_ROUTE = 449, // Routing error SMTP_MBOXBUSY = 450, // Requested mail action not taken: mailbox unavailable (E.g., mailbox busy) SMTP_PROCERROR = 451, // Requested action aborted: local error in processing SMTP_NOSPACE = 452, // Action not taken: no space left SMTP_CLIENT_ERR = 471, // Some SMTP servers return this in respose to errors on the part of the connecting client (as they see it).
// Permanent Errors SMTP_BADCOMMAND = 500, // Syntax error, command unrecognized (This may include errors such as cmd line too long) SMTP_BADSYNTAX = 501, // Syntax error in parameters or arguments SMTP_NOCOMMAND = 502, // Command not implemented SMTP_BAD_CMD_SEQ = 503, // Bad sequence of commands SMTP_BAD_PARAM = 504, // Command parameter not implemented
SMTP_BAD_SNDR_ADDR = 510, // Bad email address SMTP_BAD_RCPT_ADDR = 511, // Bad email address SMTP_BAD_HOST = 512, // Host server for the recipients domain name cannot be found in DNS SMTP_BAD_ADDR_TYPE = 513, // Address type is incorrect SMTP_MSG_SIZE = 523, // Size of your mail exceeds the server limits SMTP_BAD_SERVER = 530, // Authentication problem SMTP_BAD_SENDER = 541, // The recipient address rejected your message
SMTP_NACK = 550, // Non-existent email address SMTP_TRYOTHER = 551, // User not local or address invalid. SMTP_MBOXFULL = 552, // Requested mail action aborted: exceeded storage allocation SMTP_BADNAME = 553, // Mailbox name not allowed (E.g., mailbox syntax incorrect) SMTP_FAILED = 554, // Transaction failed (Or in the case of a connection-opening response, No SMTP service)
SMTP_INVALID = 999 // Not a 3 digit entity } ;
/* ** Email item */
enum hzContentType { // Category: Internet // // The hzContentType enumeration refers to the MIME type of files and includes MIME types used in constructing emails
HZ_CONTENT_TYPE_UNDEFINED, // Content type not defined
// For body email parts HZ_CONTENT_TYPE_TEXT_PLAIN, // Content is in plain text and there are no further levels HZ_CONTENT_TYPE_TEXT_HTML, // Content is in HTML and there are no further levels HZ_CONTENT_TYPE_IMAGE_GIF, // Content is an image (gif) HZ_CONTENT_TYPE_IMAGE_JPEG, // Content is an image (jpeg) HZ_CONTENT_TYPE_IMAGE_PNG, // Content is an image (png) HZ_CONTENT_TYPE_IMAGE_ICO, // Content is an image (ico) HZ_CONTENT_TYPE_SCRIPT_JS, // Content is a java script HZ_CONTENT_TYPE_APP_MSWORD, // Content is an application file (ms-word document) HZ_CONTENT_TYPE_APP_MSEXCEL, // Content is an application file (ms-excel document) HZ_CONTENT_TYPE_APP_PDF, // Content is an application file (pdf) HZ_CONTENT_TYPE_APP_TAR, // Content is an application file (tar) HZ_CONTENT_TYPE_APP_GZIP, // Content is an application file (gzipped) HZ_CONTENT_TYPE_APP_ZIP, // Content is an application file (zipped)
// For headers only HZ_CONTENT_TYPE_MULTI_ALTERNATIVE, // Content is presented more than once in different parts with each part representing a different format (eg text and HTML). HZ_CONTENT_TYPE_MULTI_MIXED, // The content is comprised of parts that may be dissimilar in format HZ_CONTENT_TYPE_MULTI_RELATED, // The content is comprised of related parts (only applies to email root part) } ;
enum hzContentEncoding { // Category: Internet // // The hzContentEncoding enumeration describes what form of text encoding is being used (in emails inter alia)
HZ_CONTENT_ENCODE_UNDEFINED, // Content encoding not defined HZ_CONTENT_ENCODE_7BIT, // Content is not encoded but chars are limited to lower ASCII HZ_CONTENT_ENCODE_8BIT, // Content is not encoded and chars may be upper ASCII HZ_CONTENT_ENCODE_BINARY, // Content is not encoded and chars may be anything HZ_CONTENT_ENCODE_BASE64, // Content is encoded as base64 HZ_CONTENT_ENCODE_QUOTE_PRINT, // Content is encoded as 'quoted-prinatble' meaning that chars ? and = are escaped } ;
class hzEmpart { // Category: Internet // // Component of an IMF message (email)
public: hzChain m_Content ; // The content of the email part hzString m_Filename ; // Filename hzString m_ContType ; // Type of content (eg text/plain) hzContentEncoding m_Encoding ; // Method of encoding (eg base64)
hzEmpart (void) { m_Encoding = HZ_CONTENT_ENCODE_UNDEFINED ; }
~hzEmpart (void) { Clear() ; }
void Clear (void) { m_Encoding = HZ_CONTENT_ENCODE_UNDEFINED ; m_ContType.Clear() ; m_Content.Clear() ; m_Filename.Clear() ; }
hzEmpart& operator= (const hzEmpart& op) { m_Content = op.m_Content ; m_Filename = op.m_Filename ; m_ContType = op.m_ContType ; m_Encoding = op.m_Encoding ;
return *this ; } } ;
class hzEmail { // Category: Internet // // hzEmail is a single email message container, used to compose email messages prior to sending, and for deconstruction of recieved email messages into their component parts. // // In the send case, the hzEmail instance starts out empty and the message is built in a step by step process. The sender is set, recipients are added one by one, the subject // is set, the text body is added, the HTML body is added (optional), then attachments (if any) are added one by one. Finally hzEmail::Compose() is called to assemble an IMF // message, ready for SMTP relay. // // In the recv case, hzEmail::Import() processes an IMF message to populate the set of headers and parts, thereby availing these to the application. // // Note that four hzEmail members are used for email addresses related to the sender, three of which are set by SMTP headers in the IMF message as follows:- // // m_AddrReturn is set by Return-path; // m_AddrReply is set by Reply-To; // m_AddrFrom is set by From. // // The forth, m_AddrRelay is set at the start of an SMTP client session (message incoming). It is used to set m_AddrFrom if the relayed IMF lacks the From: header, but will be // ignored otherwise. // // m_AddrFrom is the definative sender address. HadronZoo::Epistula stores the m_AddrFrom value as the sender in its message repository, and in the webmail service, this value // appears in the folder listings. In the construction of an outgoing message, m_AddrFrom is set by hzEmail::SetSender(). In the subsequent relay session, the m_AddrFrom value // is used as the initiator address. m_AddrReply and m_AddrReturn are set separately. m_AddrReply can be NULL but if m_AddrReturn is NULL, it will assume the m_AddrFrom value.
struct _efile { // Attachment description
hzString m_Filepath ; // Full pathname of file as given by AddAttachment() or as supplied in an incoming message hzMimetype m_eType ; // File type } ;
hzList <hzEmaddr> m_Recipients ; // List of main recipient(s) hzList <hzEmaddr> m_CC ; // List of cc recipient(s) hzList <hzEmaddr> m_BCC ; // List of bcc recipient(s) hzList <_efile> m_SendAttach ; // List of file attachments (added by Attach() as part of forming an outgoing email)
// Support functions hzEcode _part_process (chIter& zi, const hzString& mark, uint32_t nLevel) ;
public: hzList <hzEmpart> m_Attach ; // List of message parts that are attached files hzList <hzEmpart> m_Inline ; // List of message parts (inline) hzVect <hzPair> m_Hdrs ; // Message headers: Note this is only filled by Import. Composure of an outgoing message does not populate this list.
hzChain m_Final ; // Fully composed email (IMF) hzChain m_Text ; // Body of email (Text part) hzChain m_Html ; // Body of email (Html part) hzChain m_Err ; // For error reporting (e.g. failed import) hzXDate m_Date ; // Date of email (recv only) hzEmaddr m_AddrRelay ; // Sender address as stated at the outset of the SMTP client session. In outgoing messages, this is always the same as m_AddrFrom. hzEmaddr m_AddrReturn ; // Return address (Return-path header) hzEmaddr m_AddrReply ; // Address given in the ReplyTo header hzEmaddr m_AddrFrom ; // Authorative address of sender, as given by From header hzEmaddr m_AddrTo ; // Address of primary recipient hzString m_Id ; // Mail id (typically as set by first SMTP server to handle it) hzString m_DomainOrig ; // Domain part of m_AddrRelay (see below). Note for the message to be accepted, the domain part of m_AddrReturn, m_AddrReply, and m_AddrFrom must concur. hzString m_RealReply ; // Real name given in Reply-To header (if any) hzString m_RealFrom ; // Real name of sender hzString m_RealTo ; // Real name of recipient (rarely used) hzString m_Subject ; // Subject hzIpaddr m_SenderIP ; // Sender IP address
hzContentType m_ContType ; // Content type hzContentEncoding m_Encoding ; // Content encoding
hzEmail (void) { m_ContType = HZ_CONTENT_TYPE_UNDEFINED ; m_Encoding = HZ_CONTENT_ENCODE_UNDEFINED ; }
~hzEmail (void) { Clear() ; }
void Clear (void) ;
uint32_t CountRecipientsStd (void) const { return m_Recipients.Count() ; } uint32_t CountRecipientsCC (void) const { return m_CC.Count() ; } uint32_t CountRecipientsBC (void) const { return m_BCC.Count() ; } uint32_t CountRecipientsAll (void) const { return m_Recipients.Count() + m_CC.Count() + m_BCC.Count() ; }
// Functions to compile and send an email hzEcode SetSender (hzEmaddr& sender) { m_AddrFrom = sender ; return m_AddrFrom? E_OK : E_NODATA ; }
hzEcode SetSender (const char* cpSender, const char* cpRealname) ; hzEcode AddRecipient (hzEmaddr& recipient) ; hzEcode AddRecipientCC (hzEmaddr& recipient) ; hzEcode AddRecipientBCC (hzEmaddr& recipient) ;
hzEcode AddRecipient (const char* cpRecipient) ; hzEcode AddRecipientCC (const char* cpRecipient) ; hzEcode AddRecipientBCC (const char* cpRecipient) ;
hzEcode SetSubject (const char* cpSublect) ; hzEcode AddBody (hzChain& Z) ; hzEcode AddBody (hzString& S) ; hzEcode AddBody (const char* cpText) ; hzEcode AddAttachment (const char* cpDir, const char* cpFilename, hzMimetype eType) ; hzEcode AddAttachment (const char* cpFilepath, hzMimetype eType) ; hzEcode AddAttachment (const char* cpFilepath) ; hzEcode Compose (void) ; hzEcode SendSmtp (const char* cpMailserver, const char* username, const char* password) ; hzEcode SendEpistula (hzChain& report) ;
// Functions to load a recived email and extract headers and parts from it hzEcode Import (const hzChain& Z, bool bHead = false) ;
// Get functions hzEmaddr& GetSender (void) { return m_AddrFrom ; } hzString& GetSenderReal (void) { return m_RealFrom ; } hzString& GetSubject (void) { return m_Subject ; }
hzList<hzEmaddr>& GetRecipientsStd (void) { return m_Recipients ; } hzList<hzEmaddr>& GetRecipientsCC (void) { return m_CC ; } hzList<hzEmaddr>& GetRecipientsBCC (void) { return m_BCC ; } } ;
class hzPop3Acc { // Category: Internet // // POP3 Account. // // The hzPop3Acc (POP3 account) class enables applications to operate as a POP3 email client and recieve email messages from a POP3 server. Each hzPop3Acc // instance comprises a single username and password pair and so can only access a single 'mailbox' or 'email account'. What constitutes a mailbox or email // account is strictly a matter for the POP3 server. Some POP3 servers such as Epistula, have user centric mailboxes that can span multiple recipient email // addresses. Other POP3 servers have address centric mailboxes which will only contain email messages for a single recipient email address. // // hzPop3Acc specifies a single file into which all emails for the account are aggregated and maintains a set of email ids for lookups and to avoid repeat // downloads. The email messages themselves are available to the application as populated hzEmail instances.
hzSet<hzString> m_Already ; // IDs of already downloaded messages
hzString m_Server ; // Hostname for the account hzString m_Username ; // Username for the account hzString m_Password ; // Password for the account hzString m_Repos ; // Pathname of repository
public: hzChain m_Error ; // For error messages arising in a POP3 session
hzPop3Acc (void) {} ~hzPop3Acc (void) {}
hzEcode Init (hzString Server, hzString Username, hzString Password, hzString Repos) ;
uint32_t Count (void) const { return m_Already.Count() ; }
// Collect (download) emails hzEcode Collect (hzVect<hzString>& messages) ;
// Fetch a downloaded email or header hzEcode GetEmail (hzEmail& em, hzString& mailId) ; } ;
/* ** Prototypes */
void CreateMessageID (hzString& mailId, const hzDomain& domain) ; #endif // hzMailer_h