2

I am trying to use the Poco library to send an email. Platform is OS X, Yosemite 10.10.2 I am using Qt 5.3 32 bit. I followed the official instructions from here, and since I am using 32 bit Qt, and want the libraries to be statically linked, I used

./configure --omit=Data/ODBC,Data/MySQL --config=Darwin32

(I don't require the MySQL/ODBC modules). And it installed in /usr/local correctly, following which I linked the necessary dynamic libraries (PocoNet and PocoFoundation and 10 other libraries), and tried this following code, which I found here. What I am trying to do is send an email to my gmail account from my account itself:

#include "MailSender.hpp"

#include <Poco/Net/MailMessage.h>
#include <Poco/Net/MailRecipient.h>
#include <Poco/Net/SMTPClientSession.h>
#include <Poco/Net/NetException.h>
#include <Poco/Net/SecureSMTPClientSession.h>
#include <Poco/Net/InvalidCertificateHandler.h>
#include <Poco/Net/AcceptCertificateHandler.h>
#include <Poco/Net/SSLManager.h>
#include <Poco/Net/SecureStreamSocket.h>
#include <Poco/Net/MailRecipient.h>

#include <iostream>
#include <QDebug>

using Poco::Net::InvalidCertificateHandler;
using Poco::Net::AcceptCertificateHandler;
using Poco::Net::Context;
using Poco::Net::SSLManager;
using Poco::Net::SecureStreamSocket;
using Poco::Net::SocketAddress;
using Poco::Net::SecureSMTPClientSession;
using Poco::Net::SMTPClientSession;
using Poco::SharedPtr;
using Poco::Net::MailMessage;
using Poco::Net::MailRecipient;
using namespace std;

MailSender::MailSender()
{
SharedPtr<InvalidCertificateHandler> pCert = new AcceptCertificateHandler(false);

string host = "smtp.gmail.com";
int port = 25;

Context::Ptr pContext = new Poco::Net::Context(Context::CLIENT_USE, "", "", "", Context::VERIFY_NONE, 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
SSLManager::instance().initializeClient(0, pCert, pContext);

Poco::Net::SecureSMTPClientSession* pSecure = new Poco::Net::SecureSMTPClientSession(host, port);
Poco::Net::SecureSMTPClientSession* pSession_ = new Poco::Net::SecureSMTPClientSession(host, port);

SecureStreamSocket* pSSLSocket = new SecureStreamSocket(pContext);
pSSLSocket->connect(SocketAddress(host, port));
pSecure = new SecureSMTPClientSession(*pSSLSocket);
pSession_ = pSecure;
pSecure->login();
if (!pSecure->startTLS(pContext))
   throw std::string("Failed to start TLS connection.");

std::string sUserName = "my_email_id";
std::string sPassword = "my_password";

pSession_->login(SMTPClientSession::AUTH_LOGIN, sUserName, sPassword);


string to = "my_email_id";
string from = "my_email_id";
string subject = "Your first e-mail message sent using Poco Libraries";
subject = MailMessage::encodeWord(subject, "UTF-8");
string content = "Well done! You've successfully sent your first message using Poco SMTPClientSession";
MailMessage message;
message.setSender(from);
message.addRecipient(MailRecipient(MailRecipient::PRIMARY_RECIPIENT, to));
message.setSubject(subject);
message.setContentType("text/plain; charset=UTF-8");
message.setContent(content, MailMessage::ENCODING_8BIT);



try {
    pSession_->sendMessage(message);
    pSession_->close();
} catch (Poco::Net::SMTPException &e) {
    qDebug() << e.displayText().c_str() << endl;
}
catch (Poco::Net::NetException &e) {
    qDebug() << e.displayText().c_str() << endl;
}

}

When I run this, I get the following error:

libc++abi.dylib: terminating with uncaught exception of type Poco::Net::SSLException: SSL Exception in the Qt console.

The Apple generated crash dump shows this:

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib          0x9b7f369a __pthread_kill + 10
1   libsystem_pthread.dylib         0x90a04f19 pthread_kill + 101
2   libsystem_c.dylib               0x96861eee abort + 156
3   libc++abi.dylib                 0x965782f9 abort_message + 169
4   libc++abi.dylib                 0x9659b483 default_terminate_handler() + 272
5   libc++abi.dylib                 0x96598ac0 std::__terminate(void (*)()) + 14
6   libc++abi.dylib                 0x965986ee __cxa_rethrow + 103
7   libPocoNetSSL.30.dylib          0x02c253ff Poco::Net::SecureSocketImpl::connectSSL(bool) + 943
8   libPocoNetSSL.30.dylib          0x02c24fee Poco::Net::SecureSocketImpl::connect(Poco::Net::SocketAddress const&, bool) + 94
9   libPocoNetSSL.30.dylib          0x02c28a61 Poco::Net::SecureStreamSocketImpl::connect(Poco::Net::SocketAddress const&) + 49
10  libPocoNet.30.dylib             0x02b1368b Poco::Net::StreamSocket::connect(Poco::Net::SocketAddress const&) + 27

Somehow, the code fails at pSSLSocket->connect(SocketAddress(host, port));

I have linked PocoNet, PocoNetSSL, PocoFoundation, etc., in all, all 12 dynamic libraries generated.

Any idea how I fix this?

SexyBeast
  • 7,913
  • 28
  • 108
  • 196
  • I don't think the gmail server accepts plain-text login, so you probably want to try that with `SecureSMTPClientSession` instead of `SMTPClientSession`. I'm also not sure how happy `smtp.gmail.com` will be that you tell it you're `smtp.gmail.com` in the `HELO`. – Wintermute Mar 27 '15 at 14:16
  • That's another problem, it seems there is a `SecureSMTPClientSession` module somewhere, as I have been Googling all day, but I don't see it anywhere. Not in `Poco/Net` at least. – SexyBeast Mar 27 '15 at 14:18
  • It's part of the `NetSSL_OpenSSL` library, found in `Poco/Net/SecureSMTPClientSession.h`, as mentioned in [the documentation](http://pocoproject.org/docs/Poco.Net.SecureSMTPClientSession.html). – Wintermute Mar 27 '15 at 14:46
  • That's what I said, there is no file named `SecureSMTPClientSession.h` in my `Net` folder.. – SexyBeast Mar 27 '15 at 14:48
  • You only installed `Net` and `Foundation`. You also need `NetSSL_OpenSSL`. – Wintermute Mar 27 '15 at 14:51
  • How do I install `NetSSL_OpenSSL`? I did not do anything specific to install `Net` and `Foundation`, I just followed the official instructions and they got installed. – SexyBeast Mar 27 '15 at 14:56
  • When you downloaded the tarball, did you pick the basic edition (which does not include the crypto stuff) or the complete edition (which does)? – Wintermute Mar 27 '15 at 14:59
  • Umm, right, basic edition..Shall I try the the complete one then? – SexyBeast Mar 27 '15 at 15:24
  • Yes, you need NetSSL_OpenSSL – Alex Mar 28 '15 at 13:32
  • I tried, and got some errors - http://stackoverflow.com/questions/29307014/poco-unable-to-build-32-bit-version-with-netssl-openssl-for-os-x – SexyBeast Mar 28 '15 at 13:44

1 Answers1

5

For building, there was a bug building NetSSL examples in static build configuration (not critical but the OP did not know how to work around it), see resolved GitHub issue.

For sending email, see SecureSMTPClientSession with GMail and SSL on Poco forum:

using Poco::Net::InvalidCertificateHandler;
using Poco::Net::AcceptCertificateHandler;
using Poco::Net::Context;
using Poco::Net::SSLManager;
using Poco::Net::SecureStreamSocket;
using Poco::Net::SocketAddress;
using Poco::Net::SecureSMTPClientSession;
using Poco::Net::SMTPClientSession;
using Poco::SharedPtr;

SharedPtr<InvalidCertificateHandler> pCert = new AcceptCertificateHandler(false);
Context::Ptr pContext = new Poco::Net::Context(Context::CLIENT_USE, "", "", "", Context::VERIFY_NONE, 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
SSLManager::instance().initializeClient(0, pCert, pContext);

SecureStreamSocket* pSSLSocket = new SecureStreamSocket(pContext);
pSSLSocket->connect(SocketAddress(sSmtpServer, nSmtpPort));
pSecure = new SecureSMTPClientSession(*pSSLSocket);
pSession_ = pSecure;
pSecure->login();
if (!pSecure->startTLS(pContext))
   throw std::string("Failed to start TLS connection.");

pSession_->login(SMTPClientSession::AUTH_LOGIN, sUserName, sPassword);
pSession_->sendMessage(*pSelectedMailMessage_);
pSession_->close();

See also NetSSL Mail example:

SharedPtr<InvalidCertificateHandler> pCert = new ConsoleCertificateHandler(false); // ask the user via console
Context::Ptr pContext = new Context(Context::CLIENT_USE, "", "", "", Context::VERIFY_RELAXED, 9, true, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
SSLManager::instance().initializeClient(0, pCert, pContext);

MailMessage message;
message.setSender(sender);
message.addRecipient(MailRecipient(MailRecipient::PRIMARY_RECIPIENT, recipient));
message.setSubject("Hello from the POCO C++ Libraries");
std::string content;
content += "Hello ";
content += recipient;
content += ",\r\n\r\n";
content += "This is a greeting from the POCO C++ Libraries.\r\n\r\n";
std::string logo(reinterpret_cast<const char*>(PocoLogo), sizeof(PocoLogo));
message.addContent(new StringPartSource(content));
message.addAttachment("logo", new StringPartSource(logo, "image/gif"));

SecureSMTPClientSession session(mailhost);
session.login();
session.startTLS(pContext);
if (!username.empty())
{
    session.login(SMTPClientSession::AUTH_LOGIN, username, password);
}
session.sendMessage(message);
session.close();
Alex
  • 5,159
  • 4
  • 25
  • 33
  • Thanks for your answer. But this code is again showing linker error, please see edit to my question.. – SexyBeast Mar 31 '15 at 05:19
  • you either did not build for i386, or you are linking with some stale binaries. Make sure you have i386/libPoco* binaries in your build tree and that you are indeed linking with those – Alex Mar 31 '15 at 11:41
  • Umm, I clearly mentioned `config=Darwin32` in my `configure` step. Is there anything else I need to do? – SexyBeast Mar 31 '15 at 11:56
  • For this example, won't `libPocoNet` and `libPocoFoundation` be sufficient for linking? Do I need all `libPoco*` libraries that were installed into my `/usr/local/`??? – SexyBeast Mar 31 '15 at 12:05
  • No, they will not be sufficient, you need libPocoNetSSL, that was already said. Where your binaries are doesn't matter as long as your linker can find them and they are for the right platform. – Alex Mar 31 '15 at 13:33
  • Sorry, I was trying to take libraries from `/usr/local` after running `make -s install`, problem is, it copies only some libraries, not all. I collected them manually from `poco-develop/lib/Darwin/i386` and linked them (there are 14 libraries, excluding the debug version of each library). Now I am getting another error, see edit.. Mind you, I have omitted the ODBC/MySQL parts in the `config` step.. – SexyBeast Mar 31 '15 at 21:48
  • You are still not linking with the right binaries, linker can't find i386 code. I'm not sure why you are mentioning ODBC and MySQL. – Alex Mar 31 '15 at 22:32
  • No, I mentioned them because I don't need them, so I omitted them in the `config` step.. – SexyBeast Mar 31 '15 at 22:36
  • But I don't think I am missing any other binary. I thoroughly rebuilt everything, got 14 libs (`CppUnit`, `PocoCppParser`, `PocoCrypto`, `PocoData`, `PocoDataSQLite`, 'PocoFoundation`, `PocoJSON`, 'PocoMondoDB`, `PocoNet`, `PocoNetSSL`, `PocoPDF`, `PocoUtil`, `PocoXML` and `PocoZip`), and linked them. And they were originally in the `i386` folder in `source/lib/Darwin/` after `make -s`, so I guess the 32 bit build worked fine. – SexyBeast Mar 31 '15 at 22:39
  • Your linker can't find i386 code which should be in libPocoCrypto and libPocoNetSSL. That's the problem. You can check what is in the binaries with [lipo](http://ss64.com/osx/lipo.html) utility – Alex Mar 31 '15 at 23:16
  • I ran `lipo ~/source/lib/Poco/Poco/lib/libPocoNetSSL.a -info` and got this: **libPocoNetSSL.a is not a fat file, libPocoNetSSL.a is architecture: i386**. Same output for `PocoCrypto` as well. – SexyBeast Mar 31 '15 at 23:21
  • Then you are not linking with those libraries. What does your build command line look like? Note also that [order in which libraries are provided to the linker](http://stackoverflow.com/questions/45135/linker-order-gcc) is important when linking statically. – Alex Mar 31 '15 at 23:42
  • I am doing it through Qt, I mention the list of libraries in the `.pri` file. Here is the order in which I am linking (first to last) - `PocoFoundation`, `PocoNet`, `CppUnit`, `PocoCppParser`, `PocoCrypto`, `PocoData`, `PocoDataSQLite`, `PocoJSON`, `PocoMondoDB`, `PocoNetSSL`, `PocoPDF`, `PocoUtil`, `PocoXML` and `PocoZip`. Do I need to change it? If so, then what should be the new order? – SexyBeast Mar 31 '15 at 23:48
  • yes, if library A depends on library B, then A should appear *before* B on the command line – Alex Mar 31 '15 at 23:49
  • So here which one depends on which one? Can you specify them in the order in which I should include them? Many of them I assume are not required as well, like `PocoPDF`, etc.. – SexyBeast Mar 31 '15 at 23:50
  • Look at the [sample makefile](https://github.com/pocoproject/poco/blob/develop/NetSSL_OpenSSL/samples/TwitterClient/Makefile#L22) I fixed the other day – Alex Mar 31 '15 at 23:52
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/74217/discussion-between-cupidvogel-and-alex). – SexyBeast Mar 31 '15 at 23:55
  • Hi, I changed them to dynamic libraries and now the linking is okay, but still throws an error at connect. Please see edit. Any idea how to fix this? – SexyBeast Apr 02 '15 at 21:52
  • Can you comment on the use of `pSession_` and `pSecure` as separate things? They don't make a lot of sense to me in your first example, especially since in the second they are one and the same session object. – omatai May 02 '17 at 03:19
  • This answer really helped me, the second code worked very well with hotmail/outlook , i just had to set the port in SecureSMTPClientSession at 587 – Sorann753 Nov 20 '21 at 22:36