Skip to content

Commit

Permalink
Merge pull request #19128 from dcamper/hpcc-32678-smtp-tls
Browse files Browse the repository at this point in the history
HPCC-32678 Add support for TLS communication to Std.System.Email.SendEmail()

Reviewed-by: Gavin Halliday <ghalliday@hpccsystems.com>
Merged-by: Gavin Halliday <ghalliday@hpccsystems.com>
  • Loading branch information
ghalliday authored Sep 26, 2024
2 parents 9ce53c6 + 2c48403 commit 2484ceb
Showing 1 changed file with 99 additions and 4 deletions.
103 changes: 99 additions & 4 deletions common/remote/rmtsmtp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

#include "jlib.hpp"
#include "jlog.hpp"
#include "jsocket.hpp"
#include "securesocket.hpp"
#include "jbuff.hpp"

#include "rmtsmtp.hpp"
Expand Down Expand Up @@ -472,8 +472,9 @@ class CMailInfo
unsigned port;
StringAttr sender;
Owned<ISocket> socket;
Owned<ISecureSocketContext> secureSocketContext;
StringBuffer lastAction;
char inbuff[200];
char inbuff[2048];
unsigned inlen;
bool highPriority;
bool termJobOnFail;
Expand Down Expand Up @@ -505,6 +506,20 @@ class CMailInfo
validator.validateValue(subject.get(), "email subject");
}

void convertToTLSSocket()
{
secureSocketContext.setown(createSecureSocketContext(ClientSocket));
Owned<ISecureSocket> ssock = secureSocketContext->createSecureSocket(socket.getClear());
int status = ssock->secure_connect(SSLogNone);
if (status < 0)
{
ssock->close();
VStringBuffer errmsg("Secure connect failed: %d", status);
THROWJSOCKEXCEPTION_MSG(JSOCKERR_connection_failed, errmsg);
}
socket.setown(ssock.getClear());
}

void open()
{
SocketEndpoint address(mailServer.get());
Expand Down Expand Up @@ -633,6 +648,70 @@ class CMailInfo
out.append("HELO ").append(mailServer.get()).append("\r\n");
}

void getEhlo(StringBuffer & out) const
{
out.append("EHLO ").append(mailServer.get()).append("\r\n");
}

void processEsmtpOptions(StringBuffer & out)
{
#if defined(_USE_OPENSSL)
bool useTLS = false;
if (inlen > 12) // 12 == '250 STARTTLS'
{
// Walk the buffer, looking for the STARTTLS option
char* buffPtr = inbuff;
while (buffPtr < (inbuff + inlen - 12))
{
if (strncmp(buffPtr, "250", 3) == 0)
{
buffPtr += 3;
bool hasMoreOptions = (*buffPtr == '-');
++buffPtr;
if (strnicmp(buffPtr, "STARTTLS", 8) == 0) // case-insensitive
{
useTLS = true;
break;
}
if (hasMoreOptions)
{
// Skip to the character past the end of the line
while (buffPtr < (inbuff + inlen))
{
buffPtr++;
if (*buffPtr == '\n')
{
buffPtr++;
break;
}
}
}
else
{
break;
}
}
else
{
break;
}
}
}

if (useTLS)
{
// Tell the server we're starting TLS
out.set("STARTTLS\r\n");
writeAndAck(out.str(), out.length());
// Upgrade existing connection to TLS
convertToTLSSocket();
// Start the EHLO conversation again
getEhlo(out.clear());
writeAndAck(out.str(), out.length());
}
#endif
}

void getMailFrom(StringBuffer & out) const
{
out.append("MAIL FROM:<").append(sender.get()).append(">\r\n");
Expand Down Expand Up @@ -824,9 +903,25 @@ static void doSendEmail(CMailInfo & info, CMailPart const & part)
StringBuffer outbuff;

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

info.writeAndAck(outbuff.str(), outbuff.length());
// Try to use ESMTP and fall back to SMTP if necessary
try
{
info.getEhlo(outbuff.clear());
info.writeAndAck(outbuff.str(), outbuff.length());
info.processEsmtpOptions(outbuff);
}
catch(IException * e)
{
// Log error as a warning
StringBuffer msg;
info.addToWarnings(e->errorMessage(msg).str());
EXCLOG(MCoperatorError, e, "WARNING");
e->Release();
// Fall back to SMTP
info.getHelo(outbuff.clear());
info.writeAndAck(outbuff.str(), outbuff.length());
}

info.getMailFrom(outbuff.clear());

Expand Down

0 comments on commit 2484ceb

Please sign in to comment.