Poco не может отправить электронное письмо

Я пытаюсь использовать библиотеку Poco для отправки электронной почты. Платформа OS X, Yosemite 10.10.2. Я использую Qt 5.3 32-разрядную версию. Я следовал официальным инструкциям здесь, а так как я использую 32-битный Qt и хочу библиотеки, которые должны быть статически связаны, я использовал

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

(Мне не нужны модули MySQL/ODBC). И он установился в /usr/local правильно, после чего я связал необходимые динамические библиотеки (PocoNet и PocoFoundation и еще 10 библиотек), и попробовал этот следующий код, который я нашел здесь. То, что я пытаюсь сделать, это отправить электронное письмо на мою учетную запись gmail из моей учетной записи:

#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;
}

}

Когда я запускаю это, я получаю следующую ошибку:

libc++abi.dylib: завершение работы с необработанным исключением типа Poco::Net::SSLException: SSL Exception в консоли Qt.

Сгенерированный Apple аварийный дамп показывает это:

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

Почему-то код не работает на pSSLSocket->connect(SocketAddress(host, port));

Я связал PocoNet, PocoNetSSL, PocoFoundation и т. д., всего сгенерировано все 12 динамических библиотек.

Есть идеи, как мне это исправить?


person SexyBeast    schedule 27.03.2015    source источник
comment
Я не думаю, что сервер Gmail принимает вход в систему с помощью простого текста, поэтому вы, вероятно, захотите попробовать это с SecureSMTPClientSession вместо SMTPClientSession. Я также не уверен, насколько счастлив будет smtp.gmail.com, что вы скажете ему, что вы smtp.gmail.com в HELO.   -  person Wintermute    schedule 27.03.2015
comment
Вот еще проблема, вроде где-то есть модуль SecureSMTPClientSession, так как весь день гуглил, но нигде его не вижу. По крайней мере, в Poco/Net. ????   -  person SexyBeast    schedule 27.03.2015
comment
Это часть библиотеки NetSSL_OpenSSL, найденной в Poco/Net/SecureSMTPClientSession.h, как указано в документации. .   -  person Wintermute    schedule 27.03.2015
comment
Вот что я сказал, в моей папке Net нет файла с именем SecureSMTPClientSession.h..   -  person SexyBeast    schedule 27.03.2015
comment
Вы установили только Net и Foundation. Вам также нужно NetSSL_OpenSSL.   -  person Wintermute    schedule 27.03.2015
comment
Как установить NetSSL_OpenSSL? Я не делал ничего конкретного для установки Net и Foundation, я просто следовал официальным инструкциям, и они установились.   -  person SexyBeast    schedule 27.03.2015
comment
Когда вы загрузили tarball, вы выбрали базовую версию (которая не включает криптографию) или полную версию (которая включает)?   -  person Wintermute    schedule 27.03.2015
comment
Хм, да, базовая версия... Может, мне тогда попробовать полную?   -  person SexyBeast    schedule 27.03.2015
comment
Да, вам нужен NetSSL_OpenSSL   -  person Alex    schedule 28.03.2015
comment
Я попытался и получил несколько ошибок - stackoverflow.com/questions/29307014/   -  person SexyBeast    schedule 28.03.2015


Ответы (1)


Для сборки была ошибка сборки примеров NetSSL в статической конфигурации сборки (не критично, но ОП не знала, как ее обойти), см. исправленную GitHub проблема.

Для отправки электронной почты см. SecureSMTPClientSession с GMail и SSL на форуме Poco:

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();

См. также пример почты для NetSSL:

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();
person Alex    schedule 31.03.2015
comment
Спасибо за Ваш ответ. Но этот код снова показывает ошибку компоновщика, см. редактирование моего вопроса. - person SexyBeast; 31.03.2015
comment
вы либо не строили для i386, либо линкуете с какими-то устаревшими бинарниками. Убедитесь, что у вас есть двоичные файлы i386/libPoco* в дереве сборки и что вы действительно связываетесь с ними. - person Alex; 31.03.2015
comment
Ммм, я четко упомянул config=Darwin32 в своем configure шаге. Есть ли что-нибудь еще, что мне нужно сделать? - person SexyBeast; 31.03.2015
comment
В этом примере разве libPocoNet и libPocoFoundation будет недостаточно для связывания? Нужны ли мне все libPoco* библиотеки, которые были установлены в моем /usr/local/??? - person SexyBeast; 31.03.2015
comment
Нет, их будет недостаточно, вам нужен libPocoNetSSL, это уже было сказано. Где находятся ваши двоичные файлы, не имеет значения, если ваш компоновщик может их найти и они предназначены для правильной платформы. - person Alex; 31.03.2015
comment
Извините, я пытался взять библиотеки из /usr/local после запуска make -s install, проблема в том, что он копирует только некоторые библиотеки, а не все. Я собрал их вручную из poco-develop/lib/Darwin/i386 и слинковал (всего 14 библиотек, не считая отладочной версии каждой библиотеки). Теперь я получаю другую ошибку, см. редактирование.. Имейте в виду, я пропустил части ODBC/MySQL на шаге config.. - person SexyBeast; 01.04.2015
comment
Вы по-прежнему не линкуете нужные бинарники, компоновщик не может найти код i386. Я не уверен, почему вы упоминаете ODBC и MySQL. - person Alex; 01.04.2015
comment
Нет, я упомянул их, потому что они мне не нужны, поэтому я пропустил их на шаге config. - person SexyBeast; 01.04.2015
comment
Но я не думаю, что мне не хватает какого-либо другого двоичного файла. Я тщательно все пересобрал, получил 14 библиотек (CppUnit, PocoCppParser, PocoCrypto, PocoData, PocoDataSQLite, 'PocoFoundation, PocoJSON, 'PocoMondoDB, PocoNet, PocoNetSSL, PocoPDF, PocoUtil, PocoXML и PocoZip) и связал их. И изначально они были в папке i386 в source/lib/Darwin/ после make -s, так что я думаю, что 32-битная сборка работала нормально. - person SexyBeast; 01.04.2015
comment
Ваш компоновщик не может найти код i386, который должен быть в libPocoCrypto и libPocoNetSSL. Это проблема. Вы можете проверить, что находится в бинарниках, с помощью утилиты lipo - person Alex; 01.04.2015
comment
Я запустил lipo ~/source/lib/Poco/Poco/lib/libPocoNetSSL.a -info и получил следующее: libPocoNetSSL.a — это не толстый файл, libPocoNetSSL.a — это архитектура: i386. Тот же вывод для PocoCrypto. - person SexyBeast; 01.04.2015
comment
Тогда вы не связываетесь с этими библиотеками. Как выглядит ваша командная строка сборки? Также обратите внимание, что порядок, в котором библиотеки предоставляются компоновщику, важен при статической компоновке. - person Alex; 01.04.2015
comment
Делаю через Qt, список библиотек упоминаю в файле .pri. Вот порядок, в котором я связываю (с первого по последний) — PocoFoundation, PocoNet, CppUnit, PocoCppParser, PocoCrypto, PocoData, PocoDataSQLite, PocoJSON, PocoMondoDB, PocoNetSSL, PocoPDF, PocoUtil, PocoXML и PocoZip. Нужно ли мне его менять? Если да, то каким должен быть новый порядок? - person SexyBeast; 01.04.2015
comment
да, если библиотека A зависит от библиотеки B, то A должна появиться перед B в командной строке - person Alex; 01.04.2015
comment
Так вот какой от какого зависит? Можете ли вы указать их в том порядке, в котором я должен их включать? Я предполагаю, что многие из них также не требуются, например PocoPDF и т. д. - person SexyBeast; 01.04.2015
comment
Посмотрите на пример make-файла. Я исправил другой день - person Alex; 01.04.2015
comment
Давайте продолжим обсуждение в чате. - person SexyBeast; 01.04.2015
comment
Привет, я изменил их на динамические библиотеки, и теперь ссылка в порядке, но все равно выдает ошибку при подключении. Пожалуйста, смотрите редактирование. Есть идеи, как это исправить? - person SexyBeast; 03.04.2015
comment
Можете ли вы прокомментировать использование pSession_ и pSecure как отдельных вещей? Они не имеют для меня большого смысла в вашем первом примере, тем более что во втором они являются одним и тем же объектом сеанса. - person omatai; 02.05.2017