Skip to content

Commit

Permalink
HPCC-30377 SendEmail exception while reading from mail server
Browse files Browse the repository at this point in the history
Signed-off-by: Mark Kelly <[email protected]>
  • Loading branch information
mckellyln committed Nov 1, 2023
1 parent 0962afd commit b7c2dd8
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 84 deletions.
192 changes: 135 additions & 57 deletions common/remote/rmtsmtp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,6 @@ bool mailEncode(char const * in, StringBuffer & out)

class CMailInfo
{
StringArray *warnings;
StringArray recipients;
StringBuffer to;
StringBuffer cc;
Expand All @@ -482,8 +481,10 @@ class CMailInfo
static char const * subjectHeader;
static char const * senderHeader;
public:
CMailInfo(char const * _to, char const * _cc, char const * _bcc, char const * _subject, char const * _mailServer, unsigned _port, char const * _sender, StringArray *_warnings, bool _highPriority)
: subject(_subject), mailServer(_mailServer), port(_port), sender(_sender), lastAction("process initialization"), inlen(0), highPriority(_highPriority)
StringArray *warnings;
bool termJobOnFail;
CMailInfo(char const * _to, char const * _cc, char const * _bcc, char const * _subject, char const * _mailServer, unsigned _port, char const * _sender, StringArray *_warnings, bool _highPriority, bool _termJobOnFail)
: subject(_subject), mailServer(_mailServer), port(_port), sender(_sender), lastAction("process initialization"), inlen(0), highPriority(_highPriority), termJobOnFail(_termJobOnFail)
{
warnings = _warnings;
CSMTPValidator validator;
Expand Down Expand Up @@ -528,6 +529,17 @@ class CMailInfo
lastAction.clear().append(action);
else
lastAction.clear().append(len, out).clip();

// read any remaining bytes ...
try
{
socket->readtms(inbuff, 0, sizeof(inbuff), inlen, 0);
}
catch(IException * e)
{
e->Release();
}

try
{
socket->write(out, len);
Expand All @@ -545,30 +557,34 @@ class CMailInfo
}
}

void read()
bool read(int keepTrying)
{
try
{
socket->read(inbuff,1,sizeof(inbuff),inlen);
socket->readtms(inbuff, 1, sizeof(inbuff), inlen, 30000);

//MORE: the following is somewhat primitive and not RFC compliant (see bug 25951) - but it is a lot better than nothing
if((*inbuff == '4') || (*inbuff == '5'))
if ( (*inbuff == '5') || ((*inbuff == '4') && (!keepTrying)) )
{
StringBuffer b;
b.append("Negative reply from mail server at ").append(mailServer.get()).append(":").append(port).append(" after writing ").append(lastAction.str()).append(" in SendEmail*: ").append(inlen, inbuff).clip();
WARNLOG("%s", b.str());
if (warnings)
warnings->append(b.str());
b.append("negative reply after writing ").append(inlen, inbuff).clip();
// don't continue on after these responses ...
throw makeStringException(MSGAUD_operator, 0, b.str());
}
#ifdef SMTP_TRACE
else
{
#ifdef SMTP_TRACE
StringBuffer b(inlen, inbuff);
b.clip();
DBGLOG("SMTP read: [%s]", b.str());
}
#endif
if (*inbuff == '4')
return false;
else
return true;
}
}
catch(IException * e)
catch (IException * e)
{
int code = e->errorCode();
StringBuffer buff;
Expand Down Expand Up @@ -773,77 +789,139 @@ static const char *quit="QUIT\r\n";

static void doSendEmail(CMailInfo & info, CMailPart const & part)
{
info.open();
StringBuffer outbuff;

info.read();
info.getHelo(outbuff);
info.write(outbuff.str(), outbuff.length());
info.read();

info.getMailFrom(outbuff.clear());
info.write(outbuff.str(), outbuff.length());
info.read();

unsigned numRcpt = info.numRecipients();
for(unsigned i=0; i<numRcpt; ++i)
{
info.getRecipient(i, outbuff.clear());
info.write(outbuff.str(), outbuff.length());
info.read();
}

info.write(data, strlen(data));
info.read();
info.getHeader(outbuff.clear());
part.getHeader(outbuff);
outbuff.append("\r\n");
info.write(outbuff.str(), outbuff.length(), "mail header");
part.write(info);
info.write(endMail, strlen(endMail), "end of mail body");
info.read();

info.write(quit, strlen(quit));
info.read();
try
{
info.open();
StringBuffer outbuff;

info.read(0);
info.getHelo(outbuff);

bool ok;
int retries = 2;
while (retries >= 0)
{
info.write(outbuff.str(), outbuff.length());
ok = info.read(retries);
if (ok)
break;
retries--;
}

info.getMailFrom(outbuff.clear());

retries = 2;
while (retries >= 0)
{
info.write(outbuff.str(), outbuff.length());
ok = info.read(retries);
if (ok)
break;
retries--;
}

unsigned numRcpt = info.numRecipients();
for(unsigned i=0; i<numRcpt; ++i)
{
info.getRecipient(i, outbuff.clear());

retries = 2;
while (retries >= 0)
{
info.write(outbuff.str(), outbuff.length());
ok = info.read(retries);
if (ok)
break;
retries--;
}
}

retries = 2;
while (retries >= 0)
{
info.write(data, strlen(data));
ok = info.read(retries);
if (ok)
break;
retries--;
}

info.getHeader(outbuff.clear());
part.getHeader(outbuff);
outbuff.append("\r\n");

retries = 2;
while (retries >= 0)
{
info.write(outbuff.str(), outbuff.length(), "mail header");
part.write(info);
info.write(endMail, strlen(endMail), "end of mail body");
ok = info.read(retries);
if (ok)
break;
retries--;
}

retries = 2;
while (retries >= 0)
{
info.write(quit, strlen(quit));
ok = info.read(retries);
if (ok)
break;
retries--;
}
}
catch(IException * e)
{
if (info.termJobOnFail)
throw e;

StringBuffer msg;
if (info.warnings)
info.warnings->append(e->errorMessage(msg).str());
EXCLOG(MCoperatorError, e, "WARNING");
e->Release();
}
}

void sendEmail(const char * to, const char * cc, const char * bcc, const char * subject, const char * body, const char * mailServer, unsigned port, const char * sender, StringArray *warnings, bool highPriority)
void sendEmail(const char * to, const char * cc, const char * bcc, const char * subject, const char * body, const char * mailServer, unsigned port, const char * sender, StringArray *warnings, bool highPriority, bool termJobOnFail)
{
CMailInfo info(to, cc, bcc, subject, mailServer, port, sender, warnings, highPriority);
CMailInfo info(to, cc, bcc, subject, mailServer, port, sender, warnings, highPriority, termJobOnFail);
CTextMailPart bodyPart(body, "text/plain; charset=ISO-8859-1", NULL);
doSendEmail(info, bodyPart);
}

void sendEmail(const char * to, const char * subject, const char * body, const char * mailServer, unsigned port, const char * sender, StringArray *warnings, bool highPriority)
void sendEmail(const char * to, const char * subject, const char * body, const char * mailServer, unsigned port, const char * sender, StringArray *warnings, bool highPriority, bool termJobOnFail)
{
sendEmail(to, nullptr, nullptr, subject, body, mailServer, port, sender, warnings, highPriority);
sendEmail(to, nullptr, nullptr, subject, body, mailServer, port, sender, warnings, highPriority, termJobOnFail);
}

void sendEmailAttachText(const char * to, const char * cc, const char * bcc, const char * subject, const char * body, const char * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings, bool highPriority)
void sendEmailAttachText(const char * to, const char * cc, const char * bcc, const char * subject, const char * body, const char * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings, bool highPriority, bool termJobOnFail)
{
CMailInfo info(to, cc, bcc, subject, mailServer, port, sender, warnings, highPriority);
CMailInfo info(to, cc, bcc, subject, mailServer, port, sender, warnings, highPriority, termJobOnFail);
CTextMailPart inlinedPart(body, "text/plain; charset=ISO-8859-1", NULL);
CTextMailPart attachmentPart(attachment, mimeType, attachmentName);
CMultiMailPart multiPart(inlinedPart, attachmentPart);
doSendEmail(info, multiPart);
}

void sendEmailAttachText(const char * to, const char * subject, const char * body, const char * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings, bool highPriority)
void sendEmailAttachText(const char * to, const char * subject, const char * body, const char * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings, bool highPriority, bool termJobOnFail)
{
sendEmailAttachText(to, nullptr, nullptr, subject, body, attachment, mimeType, attachmentName, mailServer, port, sender, warnings, highPriority);
sendEmailAttachText(to, nullptr, nullptr, subject, body, attachment, mimeType, attachmentName, mailServer, port, sender, warnings, highPriority, termJobOnFail);
}

void sendEmailAttachData(const char * to, const char * cc, const char * bcc, const char * subject, const char * body, size32_t lenAttachment, const void * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings, bool highPriority)
void sendEmailAttachData(const char * to, const char * cc, const char * bcc, const char * subject, const char * body, size32_t lenAttachment, const void * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings, bool highPriority, bool termJobOnFail)
{
CMailInfo info(to, cc, bcc, subject, mailServer, port, sender, warnings, highPriority);
CMailInfo info(to, cc, bcc, subject, mailServer, port, sender, warnings, highPriority, termJobOnFail);
CTextMailPart inlinedPart(body, "text/plain; charset=ISO-8859-1", NULL);
CDataMailPart attachmentPart(lenAttachment, attachment, mimeType, attachmentName);
CMultiMailPart multiPart(inlinedPart, attachmentPart);
doSendEmail(info, multiPart);
}

void sendEmailAttachData(const char * to, const char * subject, const char * body, size32_t lenAttachment, const void * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings, bool highPriority)
void sendEmailAttachData(const char * to, const char * subject, const char * body, size32_t lenAttachment, const void * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings, bool highPriority, bool termJobOnFail)
{
sendEmailAttachData(to, nullptr, nullptr, subject, body, lenAttachment, attachment, mimeType, attachmentName, mailServer, port, sender, warnings, highPriority);
sendEmailAttachData(to, nullptr, nullptr, subject, body, lenAttachment, attachment, mimeType, attachmentName, mailServer, port, sender, warnings, highPriority, termJobOnFail);
}

12 changes: 6 additions & 6 deletions common/remote/rmtsmtp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@
#define REMOTE_API DECL_IMPORT
#endif

extern REMOTE_API void sendEmail( const char * to, const char * cc, const char * bcc, const char * subject, const char * body, const char * mailServer, unsigned port, const char * sender, StringArray *warnings=NULL, bool highPriority=false);
extern REMOTE_API void sendEmail( const char * to, const char * subject, const char * body, const char * mailServer, unsigned port, const char * sender, StringArray *warnings=NULL, bool highPriority=false);
extern REMOTE_API void sendEmail( const char * to, const char * cc, const char * bcc, const char * subject, const char * body, const char * mailServer, unsigned port, const char * sender, StringArray *warnings=NULL, bool highPriority=false, bool termJobOnFail=true);
extern REMOTE_API void sendEmail( const char * to, const char * subject, const char * body, const char * mailServer, unsigned port, const char * sender, StringArray *warnings=NULL, bool highPriority=false, bool termJobOnFail=true);

extern REMOTE_API void sendEmailAttachText(const char * to, const char * cc, const char * bcc, const char * subject, const char * body, const char * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings=NULL, bool highPriority=false);
extern REMOTE_API void sendEmailAttachText(const char * to, const char * subject, const char * body, const char * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings=NULL, bool highPriority=false);
extern REMOTE_API void sendEmailAttachText(const char * to, const char * cc, const char * bcc, const char * subject, const char * body, const char * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings=NULL, bool highPriority=false, bool termJobOnFail=true);
extern REMOTE_API void sendEmailAttachText(const char * to, const char * subject, const char * body, const char * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings=NULL, bool highPriority=false, bool termJobOnFail=true);

extern REMOTE_API void sendEmailAttachData(const char * to, const char * cc, const char * bcc, const char * subject, const char * body, size32_t lenAttachment, const void * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings=NULL, bool highPriority=false);
extern REMOTE_API void sendEmailAttachData(const char * to, const char * subject, const char * body, size32_t lenAttachment, const void * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings=NULL, bool highPriority=false);
extern REMOTE_API void sendEmailAttachData(const char * to, const char * cc, const char * bcc, const char * subject, const char * body, size32_t lenAttachment, const void * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings=NULL, bool highPriority=false, bool termJobOnFail=true);
extern REMOTE_API void sendEmailAttachData(const char * to, const char * subject, const char * body, size32_t lenAttachment, const void * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender, StringArray *warnings=NULL, bool highPriority=false, bool termJobOnFail=true);


#endif
12 changes: 6 additions & 6 deletions ecllibrary/std/system/Email.ecl
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ RETURN MODULE
* @param highPriority Optional; if true, message is sent with high priority. Defaults to false (normal priority).
*/

EXPORT SendEmail(varstring to, varstring subject, varstring body, varstring mailServer=GETENV('SMTPserver'), unsigned4 port=(unsigned4) GETENV('SMTPport', '25'), varstring sender=GETENV('emailSenderAddress'), varstring cc='', varstring bcc='', boolean highPriority=false) :=
lib_fileservices.FileServices.SendEmail(to, subject, body, mailServer, port, sender, cc, bcc, highPriority);
EXPORT SendEmail(varstring to, varstring subject, varstring body, varstring mailServer=GETENV('SMTPserver'), unsigned4 port=(unsigned4) GETENV('SMTPport', '25'), varstring sender=GETENV('emailSenderAddress'), varstring cc='', varstring bcc='', boolean highPriority=false, boolean termJobOnFail=true) :=
lib_fileservices.FileServices.SendEmail(to, subject, body, mailServer, port, sender, cc, bcc, highPriority, termJobOnFail);

/*
* Sends an email message with a text attachment using a mail server.
Expand All @@ -38,8 +38,8 @@ EXPORT SendEmail(varstring to, varstring subject, varstring body, varstring mail
* @param highPriority Optional; if true, message is sent with high priority. Defaults to false (normal priority).
*/

EXPORT SendEmailAttachText(varstring to, varstring subject, varstring body, varstring attachment, varstring mimeType, varstring attachmentName, varstring mailServer=GETENV('SMTPserver'), unsigned4 port=(unsigned4) GETENV('SMTPport', '25'), varstring sender=GETENV('emailSenderAddress'), varstring cc='', varstring bcc='', boolean highPriority=false) :=
lib_fileservices.FileServices.SendEmailAttachText(to, subject, body, attachment, mimeType, attachmentName, mailServer, port, sender, cc, bcc, highPriority);
EXPORT SendEmailAttachText(varstring to, varstring subject, varstring body, varstring attachment, varstring mimeType, varstring attachmentName, varstring mailServer=GETENV('SMTPserver'), unsigned4 port=(unsigned4) GETENV('SMTPport', '25'), varstring sender=GETENV('emailSenderAddress'), varstring cc='', varstring bcc='', boolean highPriority=false, boolean termJobOnFail=true) :=
lib_fileservices.FileServices.SendEmailAttachText(to, subject, body, attachment, mimeType, attachmentName, mailServer, port, sender, cc, bcc, highPriority, termJobOnFail);

/*
* Sends an email message with an arbitrary attachment using a mail server.
Expand All @@ -58,7 +58,7 @@ EXPORT SendEmailAttachText(varstring to, varstring subject, varstring body, vars
* @param highPriority Optional; if true, message is sent with high priority. Defaults to false (normal priority).
*/

EXPORT SendEmailAttachData(varstring to, varstring subject, varstring body, data attachment, varstring mimeType, varstring attachmentName, varstring mailServer=GETENV('SMTPserver'), unsigned4 port=(unsigned4) GETENV('SMTPport', '25'), varstring sender=GETENV('emailSenderAddress'), varstring cc='', varstring bcc='', boolean highPriority=false) :=
lib_fileservices.FileServices.SendEmailAttachData(to, subject, body, attachment, mimeType, attachmentName, mailServer, port, sender, cc, bcc, highPriority);
EXPORT SendEmailAttachData(varstring to, varstring subject, varstring body, data attachment, varstring mimeType, varstring attachmentName, varstring mailServer=GETENV('SMTPserver'), unsigned4 port=(unsigned4) GETENV('SMTPport', '25'), varstring sender=GETENV('emailSenderAddress'), varstring cc='', varstring bcc='', boolean highPriority=false, boolean termJobOnFail=true) :=
lib_fileservices.FileServices.SendEmailAttachData(to, subject, body, attachment, mimeType, attachmentName, mailServer, port, sender, cc, bcc, highPriority, termJobOnFail);

END;
Loading

0 comments on commit b7c2dd8

Please sign in to comment.