Directly relay the email to the target domain SMTP server for immediate transmission, as opposed to queuing the email to the local SMTP server. This is the fastest means of establishing the validity of the recipient address, widely used by webapps during new member registration to verify the member's email address. The following scenarios are taken into account:- 1) The DNS may be down or temporarily busy so it is not possible to determine if the domain part of the email address actually exists.# 2) The DNS provides the mail servers for the domain but none can be connected to at the moment. 3) The DNS is up but cannot find a mail server for the domain 4) The mail server was connected to but rejected the sender (the web application on your server) 5) The mail server was connected to but denied the existance of the recipient. 6) The mail server accepted the email. Of the above, scenarios 1 and 2 are inconclusive. Yet the HTTP response to the form submission (containing the user email address), must be sent without delay. The message should be queued and the user notified of this. The message should make clear the email could not be verified but if it is a live email address, the verification code will arrive in due course. Any sessions left unfullfilled after a certain period must be purged. Senarios 3, 4 and 5 are terminal. The email will not be sent at any point. Only scenario 6 is where the response can say "an email has been sent". It could be of course, that the address is incorrect. Note that bypassing the local SMTP server foregoes any email management the local SMTP server may offer. If you need a permanent and easily searchable record of the email, the calling applications will have to make arrangements for this.

Return TypeFunction nameArguments
hzEcodehzEmail::SendSmtp(const char*,const char*,const char*,)

Declared in file: hzMailer.h
Defined in file : hzMailer.cpp

Function Logic:

0:START 1:HZ_MAXPACKET HZ_MAXPACKET plog 2:unknown 3:items 4:unknown 5:rc items 6:unknown 7:rc items 8:unknown 9:rc items 10:unknown 11:rc items 12:unknown 13:rc items 14:unknown 15:Return rc 16:unknown 17:m_RealFrom 18:S rc 19:unknown 20:items 21:Return rc 22:items 23:unknown 24:rbuf 25:rbuf 26:smtpCode 27:unknown 28:items rc 29:Goto Quit 30:items 31:unknown 32:items 33:Goto Quit 34:unknown 35:items 36:unknown 37:items 38:Goto Quit 39:unknown 40:rbuf 41:rbuf 42:smtpCode 43:unknown 44:rc items 45:Goto Quit 46:unknown 47:items 48:unknown 49:unknown 50:items 51:items 52:unknown 53:items 54:Goto Quit 55:unknown 56:items 57:items 58:unknown 59:rbuf 60:rbuf 61:smtpCode 62:unknown 63:items 64:unknown 65:rc items 66:Goto Quit 67:items items inp items items S 68:unknown 69:items 70:Goto Quit 71:unknown 72:items 73:items 74:unknown 75:rbuf 76:rbuf 77:unknown 78:items 79:smtpCode 80:unknown 81:items rc 82:Goto Quit 83:items items inp items items S 84:unknown 85:items 86:Goto Quit 87:unknown 88:items 89:items 90:unknown 91:rbuf 92:rbuf 93:unknown 94:items 95:smtpCode 96:unknown 97:items rc 98:Goto Quit 99:items 100:unknown 101:items 102:Goto Quit 103:unknown 104:items 105:items 106:unknown 107:rbuf 108:rbuf 109:unknown 110:items 111:smtpCode 112:unknown 113:items rc 114:Goto Quit 115:unknown 116:e items items 117:unknown 118:items 119:rc 120:unknown 121:items 122:Goto Quit 123:unknown 124:rbuf 125:rbuf 126:unknown 127:items 128:smtpCode 129:unknown 130:items rc 131:Goto Quit 132:unknown 133:e items items 134:unknown 135:items 136:rc 137:unknown 138:items 139:Goto Quit 140:unknown 141:rbuf 142:rbuf 143:unknown 144:items 145:smtpCode 146:unknown 147:items rc 148:Goto Quit 149:unknown 150:e items items 151:unknown 152:items 153:rc 154:unknown 155:items 156:Goto Quit 157:unknown 158:rbuf 159:rbuf 160:unknown 161:items 162:smtpCode 163:unknown 164:items rc 165:Goto Quit 166:items items 167:unknown 168:items 169:items 170:unknown 171:rbuf 172:rbuf 173:unknown 174:items 175:unknown 176:items 177:ci 178:unknown 179:unknown 180:* 181:unknown 182:nTotal rc 183:unknown 184:items 185:items items 186:unknown 187:items 188:unknown 189:items 190:Goto Quit 191:items 192:unknown 193:rbuf 194:rbuf 195:unknown 196:items 197:Quit 198:items items 199:unknown 200:items 201:items 202:unknown 203:rbuf 204:rbuf 205:unknown 206:items 207:items 208:Return rc

Function body:

hzEcode hzEmail::SendSmtp (const char* server)const char* uname, const char* passwd, 
{
   //  Directly relay the email to the target domain SMTP server for immediate transmission, as opposed to queuing the email to the local SMTP server. This is the fastest means of
   //  establishing the validity of the recipient address, widely used by webapps during new member registration to verify the member's email address. The following scenarios are
   //  taken into account:-
   //  
   //   1) The DNS may be down or temporarily busy so it is not possible to determine if the domain part of the email address actually exists.#
   //   2) The DNS provides the mail servers for the domain but none can be connected to at the moment.
   //   3) The DNS is up but cannot find a mail server for the domain
   //   4) The mail server was connected to but rejected the sender (the web application on your server)
   //   5) The mail server was connected to but denied the existance of the recipient.
   //   6) The mail server accepted the email. 
   //  
   //  Of the above, scenarios 1 and 2 are inconclusive. Yet the HTTP response to the form submission (containing the user email address), must be sent without delay. The message
   //  should be queued and the user notified of this. The message should make clear the email could not be verified but if it is a live email address, the verification code will
   //  arrive in due course. Any sessions left unfullfilled after a certain period must be purged.
   //  
   //  Senarios 3, 4 and 5 are terminal. The email will not be sent at any point. Only scenario 6 is where the response can say "an email has been sent". It could be of course,
   //  that the address is incorrect.
   //  
   //  Note that bypassing the local SMTP server foregoes any email management the local SMTP server may offer. If you need a permanent and easily searchable record of the email,
   //  the calling applications will have to make arrangements for this.
   //  
   //  Arguments: 1) server The alien domain SMTP server
   //     2) uname The username for SMTP auth
   //     3) passwd The password for SMTP auth
   //  
   //  Returns: E_ARGUMENT If no server, username, password or sender is supplied or if no recipients are specified
   //     E_NOACCOUNT If the recipient does not exist
   //     E_HOSTRETRY If the server is too busy
   _hzfunc("hzEmail::SendSmtp") ;
   hzList<hzEmaddr>::Iter  rx ;        //  Recipients iterator
   hzTcpClient C ;                     //  Client connection to destination server
   hzChain     inp ;                   //  Input chain
   hzChain     oup ;                   //  Output chain
   chIter      ci ;                    //  For iterating the composed chain
   hzLogger*   plog ;                  //  Current thread logger
   char*       i ;                     //  Send buffer populator
   hzString    S ;                     //  Temporary string
   hzEmaddr    e ;                     //  Email address
   uint32_t    nRecv ;                 //  Bytes received by Recv()
   uint32_t    nSend ;                 //  Bytes sent by Send()
   uint32_t    nTotal = 0;         //  Total bytes sent (diagnostics only)
   char        sbuf[HZ_MAXPACKET+4];   //  Send buffer
   char        rbuf[HZ_MAXPACKET+4];   //  Recv buffer
   SMTPCode    smtpCode ;              //  Server SMTP return code
   hzEcode     rc = E_OK ;             //  Return code
   //  Check arguments
   plog = GetThreadLogger() ;
   if (!plog)
       Fatal("No thread logger\n") ;
   if (!server || !server[0])  { rc = E_ARGUMENT ; plog->Out("No SMTP server supplied\n") ; }
   if (!uname || !uname[0]){ rc = E_ARGUMENT ; plog->Out("No SMTP username supplied\n") ; }
   if (!passwd || !passwd[0])  { rc = E_ARGUMENT ; plog->Out("No SMTP password supplied\n") ; }
   if (!m_Recipients.Count())  { rc = E_ARGUMENT ; plog->Out("No recipients specified\n") ; }
   if (!m_AddrFrom)            { rc = E_ARGUMENT ; plog->Out("No sender address specified\n") ; }
   if (rc != E_OK)
       return rc ;
   if (!m_RealFrom)
       m_RealFrom = *m_AddrFrom ;
   //  Connect to port 25 on destination machine.
   S = server ;
   rc = C.ConnectStd(S, 25);
   if (rc != E_OK)
   {
       hzerr(rc, "Could not conect to SMTP server [%s]", server) ;
       return rc ;
   }
   //  Wait for SMTP greeting
   C.Recv(rbuf, nRecv, HZ_MAXPACKET) ;
   if (nRecv >&eq; 0)
       rbuf[nRecv] = 0;
   else
       rbuf[0]= 0;
   smtpCode = _getSmtpCode(rbuf) ;
   if (smtpCode != SMTP_READY)
   {
       plog->Out("%d Server not ready so quiting\n", smtpCode) ;
       rc = E_HOSTRETRY ;
       goto Quit ;
   }
   //  Send the EHLO command
   sprintf(sbuf, "EHLO %s\r\n", *m_AddrFrom) ;
   if ((rc = C.Send(sbuf, strlen(sbuf))) != E_OK)
   {
       plog->Out("Could not send HELO command\n") ;
       goto Quit ;
   }
   if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
       plog->Out("Client -> %s", sbuf) ;
   //  Recv the server responds
   if ((rc = C.Recv(rbuf, nRecv, HZ_MAXPACKET)) != E_OK)
   {
       plog->Out("Could not get ACK to EHLO msg\n") ;
       goto Quit ;
   }
   if (nRecv >&eq; 0)
       rbuf[nRecv] = 0;
   else
       rbuf[0]= 0;
   smtpCode = _getSmtpCode(rbuf) ;
   if (smtpCode != SMTP_OK)
       { rc = E_PROTOCOL ; plog->Out("Expected ACK so quitting\n") ; goto Quit ; }
   if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
       plog->Out("Server -> %s\n", rbuf) ;
   //  If there is an AUTH, do this first
   if (uname && passwd)
   {
       if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
           plog->Out("Have username of %s and password of %s so will auth\n", uname, passwd) ;
       strcpy(sbuf, "AUTH LOGIN\r\n") ;
       if ((rc = C.Send(sbuf, strlen(sbuf))) != E_OK)
           { plog->Out("Could not send MAIL FROM message\n") ; goto Quit ; }
       if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
           plog->Out("Client -> %s", sbuf) ;
       //  Get back the message 'send username' (written in base64)
       C.Recv(rbuf, nRecv, HZ_MAXPACKET) ;
       if (nRecv > 0)
           rbuf[nRecv] = 0;
       else
           rbuf[0]= 0;
       smtpCode = _getSmtpCode(rbuf) ;
       if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
           plog->Out("Server -> %s", rbuf) ;
       if (smtpCode != SMTP_LOGINFO)
           { rc = E_BADSENDER ; plog->Out("Expected code 334. Got instead code %d\n", smtpCode) ; goto Quit ; }
       //  Send the username
       inp.Clear() ;
       oup.Clear() ;
       inp = uname ;
       Base64Encode(oup, inp) ;
       oup << "\r\n" ;
       S = oup ;
       if ((rc = C.Send(*S, S.Length())) != E_OK)
           { plog->Out("Could not send username\n") ; goto Quit ; }
       if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
           plog->Out("Client -> %s", *S) ;
       //  Expect the message 'send password' (written in base64)
       C.Recv(rbuf, nRecv, HZ_MAXPACKET) ;
       if (nRecv > 0)
           rbuf[nRecv] = 0;
       else
           rbuf[0]= 0;
       if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
           plog->Out("Server -> %s", rbuf) ;
       smtpCode = _getSmtpCode(rbuf) ;
       if (smtpCode != SMTP_LOGINFO)
       {
           plog->Out("Expected code 334 (request for password). Got %d\n", smtpCode) ;
           rc = E_BADSENDER ;
           goto Quit ;
       }
       //  Send the password
       inp.Clear() ;
       oup.Clear() ;
       inp = passwd ;
       Base64Encode(oup, inp) ;
       oup << "\r\n" ;
       S = oup ;
       if ((rc = C.Send(*S, S.Length())) != E_OK)
           { plog->Out("Could not send password\n") ; goto Quit ; }
       if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
           plog->Out("Client -> %s", *S) ;
       //  Expect the 235 Go Ahead
       C.Recv(rbuf, nRecv, HZ_MAXPACKET) ;
       if (nRecv > 0)
           rbuf[nRecv] = 0;
       else
           rbuf[0]= 0;
       if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
           plog->Out("Server -> %s", rbuf) ;
       smtpCode = _getSmtpCode(rbuf) ;
       if (smtpCode != SMTP_GO_AHEAD)
       {
           plog->Out("Expected code 235 (Login OK, Go Ahead). Got %d\n", smtpCode) ;
           rc = E_BADSENDER ;
           goto Quit ;
       }
   }
   /*
   **  ** Now send the sender details
   **      */
   sprintf(sbuf, "MAIL FROM: <%s>\r\n", *m_AddrFrom) ;
   if ((rc = C.Send(sbuf, strlen(sbuf))) != E_OK)
       { plog->Out("Could not send MAIL FROM message\n") ; goto Quit ; }
   if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
       plog->Out("Client -> %s", sbuf) ;
   //  Expect 'sender ok'
   C.Recv(rbuf, nRecv, HZ_MAXPACKET) ;
   if (nRecv > 0)
       rbuf[nRecv] = 0;
   else
       rbuf[0]= 0;
   if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
       plog->Out("Server -> %s", rbuf) ;
   smtpCode = _getSmtpCode(rbuf) ;
   if (smtpCode != SMTP_OK)
   {
       plog->Out("Expected a 250 (OK) code. Got %d\n", smtpCode) ;
       rc = E_BADSENDER ;
       goto Quit ;
   }
   /*
   **  ** Now send the reciprient details
   **      */
   for (rx = m_Recipients ; rx.Valid() ; rx++)
   {
       e = rx.Element() ;
       sprintf(sbuf, "RCPT TO: <%s>\r\n", *e) ;
       C.Send(sbuf, strlen(sbuf)) ;
       if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
           plog->Out("Client -> %s", sbuf) ;
       //  Expect 'recipient ok'
       rc = C.Recv(rbuf, nRecv, HZ_MAXPACKET) ;
       if (rc != E_OK)
       {
           plog->Out("Broken pipe while sending recipient details\n") ;
           goto Quit ;
       }
       if (nRecv > 0)
           rbuf[nRecv] = 0;
       else
           rbuf[0]= 0;
       if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
           plog->Out("Server -> %s", rbuf) ;
       smtpCode = _getSmtpCode(rbuf) ;
       if (smtpCode != SMTP_OK && smtpCode != SMTP_GO_AHEAD)
       {
           plog->Out("Expected a 250 (OK) or 235 (Go Ahead) code. Got %d\n", smtpCode) ;
           rc = E_NOACCOUNT ;
           goto Quit ;
       }
   }
   //  Carbon copy recipients
   for (rx = m_CC ; rx.Valid() ; rx++)
   {
       e = rx.Element() ;
       sprintf(sbuf, "RCPT TO: <%s>\r\n", *e) ;
       C.Send(sbuf, strlen(sbuf)) ;
       if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
           plog->Out("Client -> %s", sbuf) ;
       //  Expect 'recipient ok'
       rc = C.Recv(rbuf, nRecv, HZ_MAXPACKET) ;
       if (rc != E_OK)
       {
           plog->Out("Broken pipe while sending recipient details\n") ;
           goto Quit ;
       }
       if (nRecv > 0)
           rbuf[nRecv] = 0;
       else
           rbuf[0]= 0;
       if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
           plog->Out("Server -> %s", rbuf) ;
       smtpCode = _getSmtpCode(rbuf) ;
       if (smtpCode != SMTP_OK)
       {
           plog->Out("Target user not ok so quiting\n") ;
           rc = E_NOACCOUNT ;
           goto Quit ;
       }
   }
   //  Blind carbon copy recipients
   for (rx = m_BCC ; rx.Valid() ; rx++)
   {
       e = rx.Element() ;
       sprintf(sbuf, "RCPT TO: <%s>\r\n", *e) ;
       C.Send(sbuf, strlen(sbuf)) ;
       if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
           plog->Out("Client -> %s", sbuf) ;
       //  Expect 'recipient ok'
       rc = C.Recv(rbuf, nRecv, HZ_MAXPACKET) ;
       if (rc != E_OK)
       {
           plog->Out("Broken pipe while sending recipient details\n") ;
           goto Quit ;
       }
       if (nRecv > 0)
           rbuf[nRecv] = 0;
       else
           rbuf[0]= 0;
       if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
           plog->Out("Server -> %s", rbuf) ;
       smtpCode = _getSmtpCode(rbuf) ;
       if (smtpCode != SMTP_OK)
       {
           plog->Out("Target user not ok so quiting\n") ;
           rc = E_NOACCOUNT ;
           goto Quit ;
       }
   }
   //  Now send the data marker
   sprintf(sbuf, "DATA\r\n") ;
   C.Send(sbuf, strlen(sbuf)) ;
   if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
       plog->Out("Client -> %s", sbuf) ;
   //  The target should ask for the mail
   //  354 Enter mail, end with "." on a line by itself
   C.Recv(rbuf, nRecv, HZ_MAXPACKET) ;
   if (nRecv > 0)
       rbuf[nRecv] = 0;
   else
       rbuf[0]= 0;
   if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
       plog->Out("Server -> %s", rbuf) ;
   //  So we send it
   if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
       plog->Out("Sending %d bytes of data\n", m_Final.Size()) ;
   //  m_Final.Rewind() ;
   //  Repeat calls to Send() to transmit email message
   ci = m_Final ;
   for (rc = E_OK ; rc == E_OK ;)
   {
       for (i = sbuf, nSend = 0; !ci.eof() && nSend < HZ_MAXPACKET ; nSend++, ci++)
           *i++ = *ci ;
       if (nSend == 0)
           break ;
       nTotal += nSend ;
       rc = C.Send(sbuf, nSend) ;
   }
   if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
       plog->Out("Sent %d of %d bytes\n", nTotal, m_Final.Size()) ;
   //  Send terminator sequence
   strcpy(sbuf, ".\r\n") ;
   C.Send(sbuf, strlen(sbuf)) ;
   if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
       plog->Out("Client -> %s", sbuf) ;
   //  rc = C.Send(m_Final) ;
   if (rc != E_OK)
   {
       plog->Out("Could not transmit msg body\n") ;
       goto Quit ;
   }
   //  Target should send us a message like
   //  250 SAA00984 Message accepted for delivery
   C.Recv(rbuf, nRecv, HZ_MAXPACKET) ;
   if (nRecv > 0)
       rbuf[nRecv] = 0;
   else
       rbuf[0]= 0;
   if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
       plog->Out("Server -> %s", rbuf) ;
Quit:
   //  Now send QUIT command
   sprintf(sbuf, "QUIT\r\n") ;
   C.Send(sbuf, strlen(sbuf)) ;
   if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
       plog->Out("Client -> %s", sbuf) ;
   //  Expect the following msg from the target
   //  221 osuks.densitron.net closing connection
   C.Recv(rbuf, nRecv, HZ_MAXPACKET) ;
   if (nRecv > 0)
       rbuf[nRecv] = 0;
   else
       rbuf[0]= 0;
   if (_hzGlobal_Debug & HZ_DEBUG_MAILER)
       plog->Out("Server -> %s", rbuf) ;
   //  It's all over!
   C.Close() ;
   return rc ;
}