mirror of
https://gitee.com/acl-dev/acl.git
synced 2024-12-02 11:57:43 +08:00
add smtp client class in lib_acl_cpp
This commit is contained in:
parent
4031cd00ff
commit
a631725ba5
@ -2,7 +2,7 @@
|
||||
#include "http_servlet.h"
|
||||
#include "master_service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ÅäÖÃÄÚÈÝÏî
|
||||
|
||||
char *var_cfg_str;
|
||||
@ -33,7 +33,7 @@ acl::master_int64_tbl var_conf_int64_tab[] = {
|
||||
{ 0, 0 , 0 , 0, 0 }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
master_service::master_service()
|
||||
{
|
||||
@ -52,7 +52,9 @@ void master_service::on_accept(acl::socket_stream* conn)
|
||||
|
||||
acl::memcache_session session("127.0.0.1:11211");
|
||||
http_servlet servlet;
|
||||
servlet.setLocalCharset("utf-8"); // charset: big5, gb2312, gb18030, gbk, utf-8
|
||||
|
||||
// charset: big5, gb2312, gb18030, gbk, utf-8
|
||||
servlet.setLocalCharset("utf-8");
|
||||
while (true)
|
||||
{
|
||||
if (servlet.doRun(session, conn) == false)
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "http_servlet.h"
|
||||
#include "master_service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ÅäÖÃÄÚÈÝÏî
|
||||
|
||||
char *var_cfg_redis_addrs;
|
||||
@ -36,7 +36,7 @@ acl::master_int64_tbl var_conf_int64_tab[] = {
|
||||
{ 0, 0 , 0 , 0, 0 }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
master_service::master_service()
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "master_service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// 配置内容项
|
||||
|
||||
char *var_cfg_str;
|
||||
@ -32,7 +32,7 @@ acl::master_int64_tbl var_conf_int64_tab[] = {
|
||||
{ 0, 0 , 0 , 0, 0 }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// acl::aio_callback 虚类的子类定义
|
||||
class io_callback : public acl::aio_callback
|
||||
@ -58,7 +58,7 @@ protected:
|
||||
{
|
||||
if (strncmp(data, "quit", 4) == 0)
|
||||
{
|
||||
// 可以显式地调用异步流的关闭过程,也可以直接返回 false,
|
||||
// 可以显式调用异步流的关闭过程,也可以直接返回 false
|
||||
// 通知异步框架自动关闭该异步流
|
||||
// client_->close();
|
||||
return false;
|
||||
@ -99,7 +99,7 @@ private:
|
||||
acl::aio_socket_stream* client_;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
master_service::master_service()
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ÅäÖÃÄÚÈÝÏî
|
||||
|
||||
extern char *var_cfg_str;
|
||||
@ -15,7 +15,7 @@ extern acl::master_int_tbl var_conf_int_tab[];
|
||||
extern long long int var_cfg_int64;
|
||||
extern acl::master_int64_tbl var_conf_int64_tab[];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//class acl::aio_socket_stream;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "master_service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ÅäÖÃÄÚÈÝÏî
|
||||
|
||||
char *var_cfg_str;
|
||||
@ -32,7 +32,7 @@ acl::master_int64_tbl var_conf_int64_tab[] = {
|
||||
{ 0, 0 , 0 , 0, 0 }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
master_service::master_service()
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ÅäÖÃÄÚÈÝÏî
|
||||
|
||||
extern char *var_cfg_str;
|
||||
@ -15,7 +15,7 @@ extern acl::master_int_tbl var_conf_int_tab[];
|
||||
extern long long int var_cfg_int64;
|
||||
extern acl::master_int64_tbl var_conf_int64_tab[];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//class acl::socket_stream;
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "rpc_manager.h"
|
||||
#include "master_service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// 配置内容项
|
||||
|
||||
char *var_cfg_str;
|
||||
@ -35,7 +35,7 @@ acl::master_int64_tbl var_conf_int64_tab[] = {
|
||||
{ 0, 0 , 0 , 0, 0 }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class request_rpc : public acl::rpc_request
|
||||
{
|
||||
@ -76,9 +76,9 @@ protected:
|
||||
// 开始处理该请求
|
||||
handle_conn(stream);
|
||||
|
||||
// 将 ACL_VSTREAM 与阻塞流对象解绑定,这样才能保证当释放阻塞流对象时
|
||||
// 不会关闭与请求者的连接,因为该连接本身是属于非阻塞流对象的,需要采
|
||||
// 用异步流关闭方式进行关闭
|
||||
// 将 ACL_VSTREAM 与阻塞流对象解绑定,这样才能保证当释放阻塞
|
||||
// 流对象时不会关闭与请求者的连接,因为该连接本身是属于非阻塞
|
||||
// 流对象的,需要采用异步流关闭方式进行关闭
|
||||
stream.unbind();
|
||||
}
|
||||
|
||||
@ -127,7 +127,7 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// acl::aio_callback 虚类的子类定义
|
||||
class io_callback : public acl::aio_callback
|
||||
@ -153,7 +153,7 @@ protected:
|
||||
{
|
||||
if (strncmp(data, "quit", len) == 0)
|
||||
{
|
||||
// 可以显式地调用异步流的关闭过程,也可以直接返回 false,
|
||||
// 可以显式调用异步流的关闭过程,也可以直接返回 false
|
||||
// 通知异步框架自动关闭该异步流
|
||||
// client_->close();
|
||||
return false;
|
||||
@ -209,7 +209,7 @@ private:
|
||||
acl::aio_socket_stream* client_;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
master_service::master_service()
|
||||
{
|
||||
@ -249,9 +249,11 @@ void master_service::proc_on_init()
|
||||
{
|
||||
// 获得异步框架的事件引擎句柄
|
||||
acl::aio_handle* handle = get_handle();
|
||||
if (handle == NULL)
|
||||
logger_fatal("aio handle null!");
|
||||
|
||||
// 初始化 rpc 服务对象
|
||||
rpc_manager::get_instance().init(handle, var_cfg_thread_pool_limit);
|
||||
rpc_manager::get_instance().init(*handle, var_cfg_thread_pool_limit);
|
||||
}
|
||||
|
||||
void master_service::proc_on_exit()
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ÅäÖÃÄÚÈÝÏî
|
||||
|
||||
extern char *var_cfg_str;
|
||||
@ -15,7 +15,7 @@ extern acl::master_int_tbl var_conf_int_tab[];
|
||||
extern long long int var_cfg_int64;
|
||||
extern acl::master_int64_tbl var_conf_int64_tab[];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//class acl::aio_socket_stream;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "master_service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ÅäÖÃÄÚÈÝÏî
|
||||
|
||||
char *var_cfg_str;
|
||||
@ -32,7 +32,7 @@ acl::master_int64_tbl var_conf_int64_tab[] = {
|
||||
{ 0, 0 , 0 , 0, 0 }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
master_service::master_service()
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// 配置内容项
|
||||
|
||||
extern char *var_cfg_str;
|
||||
@ -15,7 +15,7 @@ extern acl::master_int_tbl var_conf_int_tab[];
|
||||
extern long long int var_cfg_int64;
|
||||
extern acl::master_int64_tbl var_conf_int64_tab[];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//class acl::socket_stream;
|
||||
|
||||
@ -44,8 +44,8 @@ protected:
|
||||
virtual bool thread_on_accept(acl::socket_stream* stream);
|
||||
|
||||
/**
|
||||
* 当某个网络连接的 IO 读写超时时的回调函数,如果该函数返回 true 则表示继续等待下一次
|
||||
* 读写,否则则希望关闭该连接
|
||||
* 当某个网络连接的 IO 读写超时时的回调函数,如果该函数返回 true 则
|
||||
* 表示继续等待下一次读写,否则则希望关闭该连接
|
||||
* @param stream {socket_stream*}
|
||||
* @return {bool} 如果返回 false 则表示子类要求关闭连接,而不
|
||||
* 必将该连接再传递至 thread_main 过程
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "master_service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ÅäÖÃÄÚÈÝÏî
|
||||
|
||||
char *var_cfg_str;
|
||||
@ -32,7 +32,7 @@ acl::master_int64_tbl var_conf_int64_tab[] = {
|
||||
{ 0, 0 , 0 , 0, 0 }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
master_service::master_service()
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ÅäÖÃÄÚÈÝÏî
|
||||
|
||||
extern char *var_cfg_str;
|
||||
@ -15,7 +15,7 @@ extern acl::master_int_tbl var_conf_int_tab[];
|
||||
extern long long int var_cfg_int64;
|
||||
extern acl::master_int64_tbl var_conf_int64_tab[];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class master_service : public acl::master_trigger
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "master_service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ÅäÖÃÄÚÈÝÏî
|
||||
|
||||
char *var_cfg_str;
|
||||
@ -32,7 +32,7 @@ acl::master_int64_tbl var_conf_int64_tab[] = {
|
||||
{ 0, 0 , 0 , 0, 0 }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
master_service::master_service()
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ÅäÖÃÄÚÈÝÏî
|
||||
|
||||
extern char *var_cfg_str;
|
||||
@ -15,7 +15,7 @@ extern acl::master_int_tbl var_conf_int_tab[];
|
||||
extern long long int var_cfg_int64;
|
||||
extern acl::master_int64_tbl var_conf_int64_tab[];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//class acl::socket_stream;
|
||||
|
||||
|
@ -11,40 +11,23 @@ rpc_manager::~rpc_manager()
|
||||
{
|
||||
delete service_;
|
||||
if (handle_ != NULL)
|
||||
{
|
||||
handle_->check();
|
||||
if (internal_handle_)
|
||||
delete handle_;
|
||||
}
|
||||
logger("rpc service destroy ok!");
|
||||
}
|
||||
|
||||
void rpc_manager::init(acl::aio_handle* handle, int max_threads /* = 10 */,
|
||||
acl::aio_handle_type type /* = acl::ENGINE_SELECT */,
|
||||
void rpc_manager::init(acl::aio_handle& handle, int max_threads /* = 10 */,
|
||||
const char* addr /* = NULL */)
|
||||
{
|
||||
// 因为本类实例是单例,会在程序 main 之前被调用,
|
||||
// 所以需要在此类中打开日志
|
||||
// 创建非阻塞框架句柄
|
||||
if (handle == NULL)
|
||||
{
|
||||
logger("create new handle, max_threads: %d", max_threads);
|
||||
handle_ = new acl::aio_handle(type);
|
||||
internal_handle_ = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger("use input handle, max_threads: %d", max_threads);
|
||||
handle_ = handle;
|
||||
internal_handle_ = false;
|
||||
}
|
||||
handle_ = &handle;
|
||||
|
||||
// 创建 rpc 服务对象
|
||||
service_ = new acl::rpc_service(max_threads);
|
||||
|
||||
// 打开消息服务
|
||||
if (service_->open(handle_, addr && *addr ? addr : NULL) == false)
|
||||
logger_fatal("open service error: %s", acl::last_serror());
|
||||
else
|
||||
logger("open service ok, listening: %s!", service_->get_addr());
|
||||
logger("open service ok, listen: %s", service_->get_addr());
|
||||
}
|
||||
|
||||
void rpc_manager::fork(acl::rpc_request* req)
|
||||
|
@ -11,15 +11,12 @@ public:
|
||||
|
||||
/**
|
||||
* 单例初始化函数
|
||||
* @param handle {acl::aio_handle*} 异步引擎句柄,当该值为空时,
|
||||
* 内部会自动生成一个
|
||||
* @param handle {acl::aio_handle&} 异步引擎句柄
|
||||
* @param max_threads {int} 子线程池的最大线程数量
|
||||
* @param type {acl::aio_handle_type} 当需要内部自动创建异步引擎时,
|
||||
* 此值规定了内部所创建的异步引擎的类型,当 handle 为空时该参数
|
||||
* 没有意义
|
||||
* @param addr {const char*} rpc 服务监听的地址,如果为空,则内部由系
|
||||
* 统自动给定一个 127.0.0.1:PORT 地址进行监听,非空时则监听指定的地址
|
||||
*/
|
||||
void init(acl::aio_handle* handle, int max_threads = 10,
|
||||
acl::aio_handle_type type = acl::ENGINE_SELECT,
|
||||
void init(acl::aio_handle& handle, int max_threads = 10,
|
||||
const char* addr = NULL);
|
||||
|
||||
/**
|
||||
@ -31,7 +28,7 @@ public:
|
||||
private:
|
||||
// 异步消息句柄
|
||||
acl::aio_handle* handle_;
|
||||
bool internal_handle_;
|
||||
|
||||
// 异步 RPC 通信服务句柄
|
||||
acl::rpc_service* service_;
|
||||
};
|
||||
|
@ -1,6 +1,10 @@
|
||||
修改历史列表:
|
||||
|
||||
------------------------------------------------------------------------
|
||||
355) 2015.9.9
|
||||
355.1) feature: smtp_client 类已经可以非常方便地发送邮件
|
||||
355.2) samples/smtp_client: 测试邮件发送过程
|
||||
|
||||
354) 2015.9.7
|
||||
354.1) bugfix: geo_member::set_coordinate 中设置经纬度的参数有误
|
||||
354.2) bugfix: db_row::field_int64 之前使用的将字符串转为64位整数的方法在32位
|
||||
|
@ -7,37 +7,87 @@ namespace acl {
|
||||
class mime_code;
|
||||
class ostream;
|
||||
|
||||
/**
|
||||
* 撰写邮件时,此类用于创建与邮件附件相关的功能
|
||||
*/
|
||||
class ACL_CPP_API mail_attach
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* 构造函数
|
||||
* @param filepath {const char*} 附件文件存储路径(含文件名)
|
||||
* @param content_type {const char*} 附件文件类型
|
||||
* @param charset {const char*} 若为纯文件,此参数表明纯文本的字符集
|
||||
*/
|
||||
mail_attach(const char* filepath, const char* content_type,
|
||||
const char* charset);
|
||||
~mail_attach();
|
||||
|
||||
/**
|
||||
* 当邮件中的数据体为 multipart/relative 类型时,调用此函数设置其中的
|
||||
* html 正文中 cid 标识符
|
||||
* @param id {const char*} cid 标识符
|
||||
* @return {mail_attach&}
|
||||
*/
|
||||
mail_attach& set_content_id(const char* id);
|
||||
|
||||
/**
|
||||
* 获得构造函数传入的附件文件路径
|
||||
* @return {const char*}
|
||||
*/
|
||||
const char* get_filepath() const
|
||||
{
|
||||
return filepath_.c_str();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得附件的文件名部分经 rfc2047 编码后名称
|
||||
* @return {const char*}
|
||||
*/
|
||||
const char* get_filename() const
|
||||
{
|
||||
return filename_.c_str();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得构造函数传入的文件类型
|
||||
* @return {const char*}
|
||||
*/
|
||||
const char* get_content_type() const
|
||||
{
|
||||
return ctype_.c_str();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得由 set_content_id 设置的该附件的 cid 标识符
|
||||
* @return {const char*}
|
||||
*/
|
||||
const char* get_content_id() const
|
||||
{
|
||||
return cid_.c_str();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将附件内容采用传入的编码器进行编码后存入内存缓冲区
|
||||
* @param coder {mime_code*} 编码器(base64/qp等)
|
||||
* @param out {string&} 存储结果,采用 append 方式
|
||||
* @return {bool} 编码过程是否成功
|
||||
*/
|
||||
bool save_to(mime_code* coder, string& out);
|
||||
|
||||
/**
|
||||
* 将附件内容采用传入的编码器进行编码后存入输出流中
|
||||
* @param coder {mime_code*} 编码器(base64/qp等)
|
||||
* @param out {out&} 存储结果
|
||||
* @return {bool} 编码过程是否成功
|
||||
*/
|
||||
bool save_to(mime_code* coder, ostream& out);
|
||||
|
||||
/**
|
||||
* 创建该附件在 MIME 邮件中的文件头信息
|
||||
* @param transfer_encoding {const char*} 编码方式
|
||||
* @param out {string&} 存储结果,采用 append 方式
|
||||
*/
|
||||
void build_header(const char* transfer_encoding, string& out);
|
||||
|
||||
private:
|
||||
|
@ -9,53 +9,171 @@ namespace acl {
|
||||
class mime_code;
|
||||
class mail_attach;
|
||||
|
||||
/**
|
||||
* 邮件正文构建类
|
||||
*/
|
||||
class ACL_CPP_API mail_body
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* 构造函数
|
||||
* @param charset {const char*} 正文的字符集
|
||||
* @param encoding {const char*} 正文的编码格式
|
||||
*/
|
||||
mail_body(const char* charset = "utf-8",
|
||||
const char* encoding = "base64");
|
||||
~mail_body();
|
||||
|
||||
/**
|
||||
* 获得正文折内容类型
|
||||
* @return {const string&}
|
||||
*/
|
||||
const string& get_content_type() const
|
||||
{
|
||||
return content_type_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得正文内容类型对象
|
||||
* @return {const http_ctype&}
|
||||
*/
|
||||
const http_ctype& get_ctype() const
|
||||
{
|
||||
return ctype_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置邮件正文为 HTML 格式
|
||||
* @param html {const char*} HTML 数据
|
||||
* @param len {size_t} html 数据长度(虽然 html 是字符串格式,但提供
|
||||
* 数据长度有利于调用更灵活高效,内部不再重新通过 strlen 计算长度)
|
||||
* @return {mail_body&}
|
||||
*/
|
||||
mail_body& set_html(const char* html, size_t len);
|
||||
|
||||
/**
|
||||
* 设置邮件正文为 TEXT 格式
|
||||
* @param text {const char*} TEXT 数据
|
||||
* @param len {size_t} text 数据长度(虽然 text 是文本格式,但提供
|
||||
* 数据长度有利于调用更灵活高效,内部不再重新通过 strlen 计算长度)
|
||||
* @return {mail_body&}
|
||||
*/
|
||||
mail_body& set_text(const char* text, size_t len);
|
||||
|
||||
/**
|
||||
* 当邮件内容为 multipart/alternative 格式时调用此函数设置相应类型的
|
||||
* 正文内容
|
||||
* @param html {const char*} 正文中的 HTML 数据(非空)
|
||||
* @param hlen {size_t} html 数据长度(>0)
|
||||
* @param text {const char*} 正文中的 TEXT 数据(非空)
|
||||
* @param tlen {size_t} text 数据长度(>0)
|
||||
* @return {mail_body&}
|
||||
*/
|
||||
mail_body& set_alternative(const char* html, size_t hlen,
|
||||
const char* text, size_t tlen);
|
||||
|
||||
/**
|
||||
* 当邮件正文内容为 multipart/relative 格式时调用此函数设置正文内容
|
||||
* @param html {const char*} 正文中的 HTML 数据(非空)
|
||||
* @param hlen {size_t} html 数据长度(>0)
|
||||
* @param text {const char*} 正文中的 TEXT 数据(非空)
|
||||
* @param tlen {size_t} text 数据长度(>0)
|
||||
* @param attachments {const std::vector<mail_attach*>&} 存放
|
||||
* 与 html 中的 cid 相关的图片等附件对象
|
||||
* @return {mail_body&}
|
||||
*/
|
||||
mail_body& set_relative(const char* html, size_t hlen,
|
||||
const char* text, size_t tlen,
|
||||
const std::vector<mail_attach*>& attachments);
|
||||
|
||||
/**
|
||||
* 获得 set_html 函数设置的 html 数据
|
||||
* @param len {size_t} 存放数据长度结果
|
||||
* @return {const char*}
|
||||
*/
|
||||
const char* get_html(size_t& len) const
|
||||
{
|
||||
len = hlen_;
|
||||
return html_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 set_text 函数设置的 text 数据
|
||||
* @param len {size_t} 存放数据长度结果
|
||||
* @return {const char*}
|
||||
*/
|
||||
const char* get_text(size_t& len) const
|
||||
{
|
||||
len = tlen_;
|
||||
return text_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 set_attachments 函数设置的附件集合
|
||||
* @return {const std::vector<mail_attach*>*}
|
||||
*/
|
||||
const std::vector<mail_attach*>* get_attachments() const
|
||||
{
|
||||
return attachments_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造邮件正文并将结果追加于给定的输出流中
|
||||
* @param out {ostream&} 输出流对象
|
||||
* @return {bool} 操作是否成功
|
||||
*/
|
||||
bool save_to(ostream& out) const;
|
||||
|
||||
/**
|
||||
* 构造邮件正文并将结果追加于给定的缓冲区中
|
||||
* @param out {string&} 存储结果
|
||||
* @return {bool} 操作是否成功
|
||||
*/
|
||||
bool save_to(string& out) const;
|
||||
|
||||
/**
|
||||
* text/html 格式的邮件正文构造过程,并将结果追加于给定的缓冲区中
|
||||
* @param in {const char*} 输入的 html 格式数据
|
||||
* @param len {size_t} in 的数据长度
|
||||
* @param out {string&} 以数据追加方式存储结果
|
||||
* @return {bool} 操作是否成功
|
||||
*/
|
||||
bool save_html(const char* in, size_t len, string& out) const;
|
||||
|
||||
/**
|
||||
* text/plain 格式的邮件正文构造过程,并将结果追加于给定的缓冲区中
|
||||
* @param in {const char*} 输入的 plain 格式数据
|
||||
* @param len {size_t} in 的数据长度
|
||||
* @param out {string&} 以数据追加方式存储结果
|
||||
* @return {bool} 操作是否成功
|
||||
*/
|
||||
bool save_text(const char* in, size_t len, string& out) const;
|
||||
|
||||
/**
|
||||
* multipart/relative 格式的邮件正文构造过程,并将结果追加于给定的缓冲区中
|
||||
* @param html {const char*} 输入的 html 格式数据
|
||||
* @param hlen {size_t} html 的数据长度
|
||||
* @param text {const char*} 正文中的 TEXT 数据(非空)
|
||||
* @param tlen {size_t} text 数据长度(>0)
|
||||
* @param attachments {const std::vector<mail_attach*>&} 存放
|
||||
* 与 html 中的 cid 相关的图片等附件对象
|
||||
* @param out {string&} 以数据追加方式存储结果
|
||||
* @return {bool} 操作是否成功
|
||||
*/
|
||||
bool save_relative(const char* html, size_t hlen,
|
||||
const char* text, size_t tlen,
|
||||
const std::vector<mail_attach*>& attachments,
|
||||
string& out) const;
|
||||
|
||||
/**
|
||||
* multipart/alternative 格式的邮件正文构造过程,并将结果追加于给定的缓冲区中
|
||||
* @param html {const char*} 输入的 html 格式数据
|
||||
* @param hlen {size_t} html 的数据长度
|
||||
* @param text {const char*} 正文中的 TEXT 数据(非空)
|
||||
* @param tlen {size_t} text 数据长度(>0)
|
||||
* @param out {string&} 以数据追加方式存储结果
|
||||
* @return {bool} 操作是否成功
|
||||
*/
|
||||
bool save_alternative(const char* html, size_t hlen,
|
||||
const char* text, size_t tlen, string& out) const;
|
||||
|
||||
|
@ -11,67 +11,203 @@ class mail_attach;
|
||||
class mail_body;
|
||||
class ofstream;
|
||||
|
||||
/**
|
||||
* 邮件数据构造类,此类可以生成一封完整的邮件,同时还用于构建 SMTP 发送过程
|
||||
* 的邮件信封信息
|
||||
*/
|
||||
class ACL_CPP_API mail_message
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* 构造函数
|
||||
* @param charset {const char*} 字符集
|
||||
*/
|
||||
mail_message(const char* charset = "utf-8");
|
||||
~mail_message();
|
||||
|
||||
/**
|
||||
* 设置 SMTP 发送过程的身份验证信息
|
||||
* @param user {const char*} 邮箱账号
|
||||
* @param pass {const char*} 邮箱密码
|
||||
* @return {mail_message&}
|
||||
*/
|
||||
mail_message& set_auth(const char* user, const char* pass);
|
||||
|
||||
/**
|
||||
* 设置邮件的发送都邮箱,此字段可用于 SMTP 发送过程的 MAIL FROM 命令,
|
||||
* 同时又可作为邮件头中的 From 字段值
|
||||
* @param from {const char*} 发件人邮件地址
|
||||
* @param name {const char*} 发件人名称
|
||||
* @return {mail_message&}
|
||||
*/
|
||||
mail_message& set_from(const char* from, const char* name = NULL);
|
||||
|
||||
mail_message& set_sender(const char* sender, const char* name = NULL);
|
||||
|
||||
/**
|
||||
* 设置邮件头中的 Reply-To 字段值
|
||||
* @param reply_to {const char*} Reply-To 邮箱字段值
|
||||
* @param name {const char*} Reply-To 对应的人员名称
|
||||
* @return {mail_message&}
|
||||
*/
|
||||
mail_message& set_reply_to(const char* reply_to, const char* name = NULL);
|
||||
|
||||
/**
|
||||
* 设置邮件头中的 Return-Path 字段值
|
||||
* @param return_path {const char*} Return-Path 邮箱字段值
|
||||
* @return {mail_message&}
|
||||
*/
|
||||
mail_message& set_return_path(const char* return_path);
|
||||
|
||||
/**
|
||||
* 设置邮件头中的 Delivered-To 字段值
|
||||
* @param delivered_to {const char*} Delivered-To 邮箱字段值
|
||||
* @return {mail_message&}
|
||||
*/
|
||||
mail_message& set_delivered_to(const char* delivered_to);
|
||||
|
||||
/**
|
||||
* 添加收件人地址,该地址仅出现在信封中,不出现在邮件头中
|
||||
* @param recipients {const char*} 收件人集合,遵守 RFC822 格式
|
||||
* @return {mail_message&}
|
||||
*/
|
||||
mail_message& add_recipients(const char* recipients);
|
||||
|
||||
/**
|
||||
* 设置邮件头中的 To 字段值,同时该收件人地址集合被用于信封中作为收件人
|
||||
* @param to {const char*} 收件人邮箱地址集合,遵守 RFC822 格式
|
||||
* @return {mail_message&}
|
||||
*/
|
||||
mail_message& add_to(const char* to);
|
||||
|
||||
/**
|
||||
* 设置邮件头中的 Cc 字段值,同时该收件人地址集合被用于信封中作为收件人
|
||||
* @param cc {const char*} 收件人邮箱地址集合,遵守 RFC822 格式
|
||||
* @return {mail_message&}
|
||||
*/
|
||||
mail_message& add_cc(const char* cc);
|
||||
|
||||
/**
|
||||
* 设置邮件发送的暗送地址集合,该地址集合不会出现在邮件头中
|
||||
* @param bcc {const char*} 暗送邮箱地址集合,遵守 RFC822 格式
|
||||
* @return {mail_message&}
|
||||
*/
|
||||
mail_message& add_bcc(const char* bcc);
|
||||
|
||||
/**
|
||||
* 设置邮件头中的主题,该主题将采用 rfc2047 编码且采用类构造函数
|
||||
* 设置的字符集
|
||||
* @param subject {const char*} 邮件头主题字段值
|
||||
* @return {mail_message&}
|
||||
*/
|
||||
mail_message& set_subject(const char* subject);
|
||||
|
||||
/**
|
||||
* 用户可以调用此函数添加邮件头中的头部扩展字段值
|
||||
* @param name {const char*} 字段名
|
||||
* @param value {const char*} 字段值
|
||||
* @return {mail_message&}
|
||||
*/
|
||||
mail_message& add_header(const char* name, const char* value);
|
||||
mail_message& set_body(const mail_body* body);
|
||||
|
||||
/**
|
||||
* 设置邮件的正文对象
|
||||
* @param body {const mail_body&} 邮件正文对象
|
||||
* @return {mail_message&}
|
||||
*/
|
||||
mail_message& set_body(const mail_body& body);
|
||||
|
||||
/**
|
||||
* 给一封邮件添加一个附件
|
||||
* @param filepath {const char*} 附件全路径(非空)
|
||||
* @param content_type {const char*} 附件类型(非空)
|
||||
* @return {mail_message&}
|
||||
*/
|
||||
mail_message& add_attachment(const char* filepath,
|
||||
const char* content_type);
|
||||
|
||||
/**
|
||||
* 构造一封完整的邮件,并将邮件内容存储于给定磁盘文件中,如果该文件
|
||||
* 存在则首先会清空,否则会创建新的文件
|
||||
* @param filepath {const char*} 目标文件
|
||||
* @return {bool} 操作是否成功
|
||||
*/
|
||||
bool save_to(const char* filepath);
|
||||
|
||||
/**
|
||||
* 可以单独调用本函数用来生成邮件头数据
|
||||
* @param out {string&} 创建的邮件头数据将追加于该缓冲区中
|
||||
* @return {bool} 操作是否成功
|
||||
*/
|
||||
bool build_header(string& out);
|
||||
|
||||
/**
|
||||
* 获得所创建的邮件在磁盘上的全路径,该函数必须在调用 save_to 成功后调用
|
||||
* @return {const char*}
|
||||
*/
|
||||
const char* get_email() const
|
||||
{
|
||||
return filepath_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得用于 SMTP 身份验证时的邮箱账号
|
||||
* @return {const char*}
|
||||
*/
|
||||
const char* get_auth_user() const
|
||||
{
|
||||
return auth_user_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得用于 SMTP 身份验证时的邮箱账号密码
|
||||
* @return {const char*}
|
||||
*/
|
||||
const char* get_auth_pass() const
|
||||
{
|
||||
return auth_pass_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得由 set_from 设置的邮箱地址对象
|
||||
* @return {const rfc822_addr*}
|
||||
*/
|
||||
const rfc822_addr* get_from() const
|
||||
{
|
||||
return from_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得由 set_sender 设置的邮箱地址对象
|
||||
* @return {const rfc822_addr*}
|
||||
*/
|
||||
const rfc822_addr* get_sender() const
|
||||
{
|
||||
return sender_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得由 set_reply_to 设置的邮箱地址对象
|
||||
* @return {const rfc822_addr*}
|
||||
*/
|
||||
const rfc822_addr* get_reply_to() const
|
||||
{
|
||||
return reply_to_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得由 set_return_path 设置的邮箱地址对象
|
||||
* @return {const rfc822_addr*}
|
||||
*/
|
||||
const rfc822_addr* get_return_path() const
|
||||
{
|
||||
return return_path_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得由 set_delivered_to 设置的邮箱地址对象
|
||||
* @return {const rfc822_addr*}
|
||||
*/
|
||||
const rfc822_addr* get_delivered_to() const
|
||||
{
|
||||
return delivered_to_;
|
||||
@ -82,28 +218,45 @@ public:
|
||||
return to_list_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得由 set_cc 设置的邮箱地址对象集合
|
||||
* @return {const std::vector<rfc822_addr*>&}
|
||||
*/
|
||||
const std::vector<rfc822_addr*>& get_cc() const
|
||||
{
|
||||
return cc_list_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得由 set_bcc 设置的邮箱地址对象集合
|
||||
* @return {const std::vector<rfc822_addr*>&}
|
||||
*/
|
||||
const std::vector<rfc822_addr*>& get_bcc() const
|
||||
{
|
||||
return bcc_list_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得所有邮件接收者的地址集合
|
||||
* @return {const std::vector<rfc822_addr*>&}
|
||||
*/
|
||||
const std::vector<rfc822_addr*>& get_recipients() const
|
||||
{
|
||||
return recipients_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得用户设置的邮件头扩展字段值
|
||||
* @param name {const char*} 字段名
|
||||
* @return {const char*}
|
||||
*/
|
||||
const char* get_header_value(const char* name) const;
|
||||
|
||||
const char* get_filepath() const
|
||||
{
|
||||
return filepath_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为 MIME 数据创建唯一的分隔符
|
||||
* @param id {const char*} 调用者填写的 ID 标识
|
||||
* @param out {string&} 存储结果
|
||||
*/
|
||||
static void create_boundary(const char* id, string& out);
|
||||
|
||||
private:
|
||||
|
@ -11,20 +11,50 @@ class istream;
|
||||
class polarssl_conf;
|
||||
class mail_message;
|
||||
|
||||
/**
|
||||
* SMTP 邮件发送客户端类,可以使用此类对象发送邮件,支持身份认证等功能
|
||||
*/
|
||||
class ACL_CPP_API smtp_client
|
||||
{
|
||||
public:
|
||||
smtp_client(const char* addr, int conn_timeout, int rw_timeout);
|
||||
/**
|
||||
* 构造函数
|
||||
* @param addr {const char*} SMTP 邮件服务器地址,格式:IP:PORT
|
||||
* 或 domain:port
|
||||
* @param conn_timeout {int} 连接服务器的超时时间(秒)
|
||||
* @param rw_timeout {int} 网络 IO 超时时间(秒)
|
||||
*/
|
||||
smtp_client(const char* addr, int conn_timeout = 60,
|
||||
int rw_timeout = 60);
|
||||
~smtp_client();
|
||||
|
||||
/**
|
||||
* 调用本函数发送邮件数据至邮件服务端
|
||||
* 调用本函数发送邮件数据至邮件服务端,该函数会首先调用 send_envelop
|
||||
* 发送信封,当 email 或 message.get_email() 非空时,则会调用发送邮件
|
||||
* 过程;否则(即 email 和 message.get_email() 均为 NULL)则只发送
|
||||
* 信封
|
||||
* @param message {const mail_messsage&} 邮件相关信息,必须提前构建好
|
||||
* @param email {const char*} 非空时,优先使用此文件做为邮件体数据发送
|
||||
* @
|
||||
* @return {bool} 发送是否成功
|
||||
* 注:如果 email 为 NULL 同时 messsage.get_email() 也为 NULL,则本
|
||||
* 函数仅发送 SMTP 信封部分,用户还需要调用:
|
||||
* data_begin-->write|format|vformat|send_file-->data_end
|
||||
* 过程来发送邮件数据体
|
||||
*/
|
||||
bool send(const mail_message& message, const char* email = NULL);
|
||||
|
||||
/**
|
||||
* 在 SMTP 会话阶段仅发送邮件信封部分数据,应用调用此函数成功后,
|
||||
* 还需要调用:
|
||||
* 1、data_begin:开始发送邮件体指令
|
||||
* 2、write/format/vformat/send_file:发送邮件数据
|
||||
* 3、data_end:表示发送邮件体数据完毕
|
||||
* @param message {const mail_message&} 发送邮件所构建的邮件消息对象
|
||||
* @return {bool} 是否成功
|
||||
* 注:本函数是 open/auth_login/mail_from/rcpt_to 发送信封过程的组合
|
||||
*/
|
||||
bool send_envelope(const mail_message& message);
|
||||
|
||||
/**
|
||||
* 设置 SSL 数据传输模式
|
||||
* @param ssl_conf {polarssl_conf*} 非空时,指定采用 SSL 传输模式
|
||||
@ -44,11 +74,14 @@ public:
|
||||
*/
|
||||
const char* get_status() const;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* 发送邮件体数据,可以循环调用本函数,但数据内容必须是严格的邮件格式
|
||||
* @param data {const char*} 邮件内容
|
||||
* @param len {size_t} data 邮件数据长度
|
||||
* @return {bool} 命令操作是否成功
|
||||
* 注:在第一次调用本函数前,必须保证 SMTP 信封已经成功发送
|
||||
*/
|
||||
bool write(const char* data, size_t len);
|
||||
|
||||
@ -56,6 +89,7 @@ public:
|
||||
* 发送邮件体数据,可以循环调用本函数,但数据内容必须是严格的邮件格式
|
||||
* @param fmt {const char*} 变参格式
|
||||
* @return {bool} 命令操作是否成功
|
||||
* 注:在第一次调用本函数前,必须保证 SMTP 信封已经成功发送
|
||||
*/
|
||||
bool format(const char* fmt, ...);
|
||||
|
||||
@ -64,33 +98,80 @@ public:
|
||||
* @param fmt {const char*} 变参格式
|
||||
* @param ap {va_list}
|
||||
* @return {bool} 命令操作是否成功
|
||||
* 注:在第一次调用本函数前,必须保证 SMTP 信封已经成功发送
|
||||
*/
|
||||
bool vformat(const char* fmt, va_list ap);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 以下是打开连接和发送信封的分步步骤
|
||||
/**
|
||||
* 连接远程 SMTP 服务器
|
||||
* @return {bool} 连接是否成功,若想使用 SSL 方式,则需要在类对象
|
||||
* 初始化后调用 set_ssl 设置 SSL 通信方式
|
||||
*/
|
||||
bool open();
|
||||
|
||||
/**
|
||||
* 主动关闭与 SMTP 服务端的连接
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* 第一次连接成功后需要调用本函数获得 SMTP 服务端的欢迎信息
|
||||
* @return {bool} 是否成功
|
||||
*/
|
||||
bool get_banner();
|
||||
|
||||
/**
|
||||
* 调用 get_banner 成功后调用本函数向 SMTP 服务端发送 HELO/HELO 命令
|
||||
* @return {bool} 是否成功
|
||||
*/
|
||||
bool greet();
|
||||
|
||||
/**
|
||||
* 调用 gree 成功后调用本函数向 SMTP 服务端发送身份认证命令
|
||||
* @param user {const char*} 用户账号,非空字符串
|
||||
* @param pass {const char*} 用户账号密码,非空字符串
|
||||
* @return {bool} 是否成功
|
||||
*/
|
||||
bool auth_login(const char* user, const char* pass);
|
||||
|
||||
/**
|
||||
* 调用 auth_login 成功后(如果无身份验证,则可以在 greet 成功后)
|
||||
* 调用本函数向 SMTP 服务器发送 MAIL FROM 命令
|
||||
* @param from {const char*} 发件人的邮箱地址
|
||||
* @return {bool} 是否成功
|
||||
*/
|
||||
bool mail_from(const char* from);
|
||||
|
||||
/**
|
||||
* 调用 mail_from 成功后调用本函数向 SMTP 服务端发送 RCPT TO 命令,
|
||||
* 指明一个收件人,可以多次本函数将邮件发送至多个收件人
|
||||
* @param to {const char*} 收件人邮箱地址
|
||||
* @return {bool} 是否成功
|
||||
*/
|
||||
bool rcpt_to(const char* to);
|
||||
|
||||
/**
|
||||
* 发送一封完整的邮件,需要给出邮件存储于磁盘上的路径
|
||||
* 调用 rcpt_to 或 send_envelope 成功调用本函数向 SMTP 服务端
|
||||
* DATA 命令,表明开始发送邮件数据
|
||||
* @return {bool} 命令操作是否成功
|
||||
* 注:在调用本函数前,必须保证 SMTP 信封已经成功发送
|
||||
*/
|
||||
bool data_begin();
|
||||
|
||||
/**
|
||||
* 调用 data_begin 成功调用本函数向 SMTP 服务端发送一封完整的邮件,
|
||||
* 需要给出邮件存储于磁盘上的路径
|
||||
* @param filepath {const char*} 邮件文件路径
|
||||
* @return {bool} 命令操作是否成功
|
||||
* 注:在调用本函数前,必须保证 SMTP 信封已经成功发送
|
||||
*/
|
||||
bool send_email(const char* filepath);
|
||||
|
||||
/**
|
||||
* 开始发送邮件数据命令:DATA
|
||||
* @return {bool} 命令操作是否成功
|
||||
*/
|
||||
bool data_begin();
|
||||
/**
|
||||
* 邮件发送完毕后,最后必须调用本函数告诉邮件服务器发送数据结束
|
||||
* 邮件发送完毕(如调用:send_email)后,最后必须调用本函数告诉 SMTP
|
||||
* 邮件服务器发送数据结束
|
||||
* @return {bool} 命令操作是否成功
|
||||
*/
|
||||
bool data_end();
|
||||
@ -121,6 +202,7 @@ private:
|
||||
SMTP_CLIENT* client_;
|
||||
socket_stream stream_;
|
||||
bool ehlo_;
|
||||
bool reuse_;
|
||||
|
||||
bool to_recipients(const std::vector<rfc822_addr*>& recipients);
|
||||
};
|
||||
|
@ -18,8 +18,6 @@ public:
|
||||
istream() {}
|
||||
virtual ~istream() {}
|
||||
|
||||
int read();
|
||||
|
||||
/**
|
||||
* 从输入流中读数据
|
||||
* @param buf {void*} 用户缓冲区
|
||||
@ -140,7 +138,8 @@ public:
|
||||
|
||||
/**
|
||||
* 从输入流中读一个字节数据
|
||||
* @return {int} 所读字节的 ASCII 码值
|
||||
* @return {int} 所读字节的 ASCII 码值,如果返回值为 -1 则表示对方关闭或
|
||||
* 读出错
|
||||
*/
|
||||
int getch(void);
|
||||
|
||||
|
@ -18,7 +18,7 @@ static void build_html(void)
|
||||
const char* html = "<html><body>中国人民银行 HTML 格式</body></html>";
|
||||
acl::mail_body body("gbk");
|
||||
body.set_html(html, strlen(html));
|
||||
message.set_body(&body);
|
||||
message.set_body(body);
|
||||
|
||||
const char* filepath = "./html.eml";
|
||||
if (message.save_to(filepath) == false)
|
||||
@ -41,7 +41,7 @@ static void build_text(void)
|
||||
const char* text = "中国人民银行 TEXT 格式";
|
||||
acl::mail_body body("gbk");
|
||||
body.set_text(text, strlen(text));
|
||||
message.set_body(&body);
|
||||
message.set_body(body);
|
||||
|
||||
const char* filepath = "./text.eml";
|
||||
if (message.save_to(filepath) == false)
|
||||
@ -67,7 +67,7 @@ static void build_alternative(void)
|
||||
const char* html = "<html><body>中国人民银行 HTML 格式</body></html>";
|
||||
acl::mail_body body("gbk");
|
||||
body.set_alternative(html, strlen(html), text, strlen(text));
|
||||
message.set_body(&body);
|
||||
message.set_body(body);
|
||||
|
||||
const char* filepath = "./alternative.eml";
|
||||
if (message.save_to(filepath) == false)
|
||||
@ -182,7 +182,7 @@ static void build_relative(void)
|
||||
acl::mail_body body("gbk");
|
||||
body.set_relative(html.c_str(), html.size(),
|
||||
text.c_str(), text.size(), attachments);
|
||||
message.set_body(&body);
|
||||
message.set_body(body);
|
||||
|
||||
const char* filepath = "./relative.eml";
|
||||
if (message.save_to(filepath) == false)
|
||||
|
@ -8,67 +8,100 @@ static acl::polarssl_conf ssl_conf;
|
||||
static bool send_mail(const char* addr, const char* sender, const char* pass,
|
||||
const char* recipients, bool use_ssl)
|
||||
{
|
||||
acl::smtp_client conn(addr, 60, 60);
|
||||
|
||||
if (use_ssl)
|
||||
conn.set_ssl(&ssl_conf);
|
||||
|
||||
conn.set_auth(sender, pass)
|
||||
acl::mail_message message("gbk");
|
||||
message.set_auth(sender, pass)
|
||||
.set_from(sender)
|
||||
.add_recipients(recipients);
|
||||
|
||||
if (conn.send_envelope() == false)
|
||||
acl::smtp_client conn(addr, 60, 60);
|
||||
|
||||
// 设置是否采用 SSL 通信方式
|
||||
if (use_ssl)
|
||||
conn.set_ssl(&ssl_conf);
|
||||
|
||||
// 发送信封
|
||||
if (conn.send_envelope(message) == false)
|
||||
{
|
||||
printf("send envelope error: %d, %s\r\n",
|
||||
conn.get_smtp_code(), conn.get_smtp_status());
|
||||
conn.get_code(), conn.get_status());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 开始发送邮件体数据
|
||||
if (conn.data_begin() == false)
|
||||
{
|
||||
printf("send data begin error: %d, %s\r\n",
|
||||
conn.get_smtp_code(), conn.get_smtp_status());
|
||||
conn.get_code(), conn.get_status());
|
||||
}
|
||||
|
||||
const char* data = "From: <zsxxsz@263.net>\r\n"
|
||||
"To: zsxxsz@263.net\r\n"
|
||||
"Subject: hello, world!\r\n"
|
||||
const char* data = "From: \"郑树新1\" <zsxxsz@263.net>\r\n"
|
||||
"To: \"郑树新2\" <zsxxsz@263.net>\r\n"
|
||||
"Subject: 您好,hello, world!\r\n"
|
||||
"\r\n"
|
||||
"hello world!\r\n";
|
||||
|
||||
// 发送邮件体数据
|
||||
if (conn.write(data, strlen(data)) == false)
|
||||
{
|
||||
printf("send data error: %d, %s\r\n",
|
||||
conn.get_smtp_code(), conn.get_smtp_status());
|
||||
conn.get_code(), conn.get_status());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 发送完毕
|
||||
if (conn.data_end() == false)
|
||||
{
|
||||
printf("send data end error: %d, %s\r\n",
|
||||
conn.get_smtp_code(), conn.get_smtp_status());
|
||||
conn.get_code(), conn.get_status());
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("sendmail ok, from: %s, to: %s, code: %d, status: %s\r\n",
|
||||
sender, recipients, conn.get_smtp_code(),
|
||||
conn.get_smtp_status());
|
||||
sender, recipients, conn.get_code(),
|
||||
conn.get_status());
|
||||
|
||||
// 发送 QUIT 命令
|
||||
if (conn.quit() == false)
|
||||
{
|
||||
printf("send quit error: %d, %s\r\n",
|
||||
conn.get_smtp_code(), conn.get_smtp_status());
|
||||
conn.get_code(), conn.get_status());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool send_mail(const char* addr, const char* sender, const char* pass,
|
||||
const char* recipients, const acl::string& email_path, bool use_ssl)
|
||||
{
|
||||
acl::mail_message message("utf-8");
|
||||
message.set_auth(sender, pass)
|
||||
.set_from(sender)
|
||||
.add_recipients(recipients);
|
||||
|
||||
acl::smtp_client conn(addr, 60, 60);
|
||||
|
||||
// 设置是否采用 SSL 通信方式
|
||||
if (use_ssl)
|
||||
conn.set_ssl(&ssl_conf);
|
||||
|
||||
if (conn.send(message, email_path) == false)
|
||||
{
|
||||
printf("send email %s to %s error\r\n",
|
||||
email_path.c_str(), addr);
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("send email %s to %s ok\r\n", email_path.c_str(), addr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void usage(const char* procname)
|
||||
{
|
||||
printf("usage: %s -h[help]\r\n"
|
||||
"\t-s smtp_server_addr\r\n"
|
||||
"\t-e [if use ssl]\r\n"
|
||||
"\t-f email_path\r\n"
|
||||
"\t-u sender\r\n"
|
||||
"\t-p sender_pass\r\n"
|
||||
"\t-t recipients[sample: to1@xxx.com; to2@xxx.com\r\n",
|
||||
@ -79,13 +112,13 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
int ch;
|
||||
bool use_ssl = false;
|
||||
acl::string addr("smtp.263.net:25");
|
||||
acl::string addr("smtp.263.net:25"), email_path;
|
||||
acl::string sender("zsxxsz@263.net"), pass, recipients;
|
||||
|
||||
acl::acl_cpp_init();
|
||||
acl::log::stdout_open(true);
|
||||
|
||||
while ((ch = getopt(argc, argv, "hs:u:p:t:e")) > 0)
|
||||
while ((ch = getopt(argc, argv, "hs:u:p:t:ef:")) > 0)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
@ -107,6 +140,9 @@ int main(int argc, char* argv[])
|
||||
case 'e':
|
||||
use_ssl = true;
|
||||
break;
|
||||
case 'f':
|
||||
email_path = optarg;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -118,9 +154,12 @@ int main(int argc, char* argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
(void) send_mail(addr.c_str(), sender.c_str(), pass.c_str(),
|
||||
recipients.c_str(), use_ssl);
|
||||
|
||||
if (email_path.empty())
|
||||
(void) send_mail(addr.c_str(), sender.c_str(), pass.c_str(),
|
||||
recipients.c_str(), use_ssl);
|
||||
else
|
||||
(void) send_mail(addr.c_str(), sender.c_str(), pass.c_str(),
|
||||
recipients.c_str(), email_path, use_ssl);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
getchar();
|
||||
|
@ -1,6 +0,0 @@
|
||||
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
||||
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
||||
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
|
||||
!_TAG_PROGRAM_NAME Exuberant Ctags //
|
||||
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
|
||||
!_TAG_PROGRAM_VERSION 5.9~svn20110310 //
|
@ -36,7 +36,7 @@ int main(int argc, char* argv[])
|
||||
printf("after set sendbuf's size: %d, readbuf's size: %d\r\n",
|
||||
client->get_tcp_sendbuf(), client->get_tcp_recvbuf());
|
||||
|
||||
if (client->write("hello world\r\n") == false)
|
||||
if (client->write("hello world\r\n") == -1)
|
||||
{
|
||||
printf("write error\r\n");
|
||||
delete client;
|
||||
|
@ -28,9 +28,7 @@ memcache_pool& memcache_pool::set_timeout(int conn_timeout /* = 30 */,
|
||||
|
||||
connect_client* memcache_pool::create_connect()
|
||||
{
|
||||
memcache* conn = NEW memcache(addr_, conn_timeout_,
|
||||
rw_timeout_);
|
||||
return conn;
|
||||
return NEW memcache(addr_, conn_timeout_, rw_timeout_);
|
||||
}
|
||||
|
||||
} // namespace acl
|
||||
|
@ -43,7 +43,7 @@ bool mail_attach::save_to(mime_code* coder, string& out)
|
||||
if (coder)
|
||||
build_header(coder->get_encoding_type(), out);
|
||||
else
|
||||
build_header("base64", out);
|
||||
build_header(NULL, out);
|
||||
|
||||
string buf;
|
||||
if (ifstream::load(filepath_.c_str(), &buf) == false)
|
||||
@ -72,7 +72,7 @@ bool mail_attach::save_to(mime_code* coder, ostream& out)
|
||||
if (coder)
|
||||
build_header(coder->get_encoding_type(), header);
|
||||
else
|
||||
build_header("base64", header);
|
||||
build_header(NULL, header);
|
||||
|
||||
if (out.write(header) == -1)
|
||||
{
|
||||
@ -140,8 +140,10 @@ void mail_attach::build_header(const char* transfer_encoding, string& out)
|
||||
{
|
||||
out.format_append("Content-Type: %s;\r\n", ctype_.c_str());
|
||||
out.format_append("\tname=\"%s\"\r\n", filename_.c_str());
|
||||
out.format_append("Content-Transfer-Encoding: %s\r\n",
|
||||
transfer_encoding);
|
||||
|
||||
if (transfer_encoding && *transfer_encoding)
|
||||
out.format_append("Content-Transfer-Encoding: %s\r\n",
|
||||
transfer_encoding);
|
||||
|
||||
if (cid_.empty())
|
||||
out.format_append("Content-Disposition: attachment;\r\n"
|
||||
|
@ -118,8 +118,8 @@ bool mail_body::save_to(string& out) const
|
||||
|
||||
void mail_body::set_content_type(const char* content_type)
|
||||
{
|
||||
content_type_.format(content_type);
|
||||
ctype_.parse(content_type_);
|
||||
content_type_ = content_type;
|
||||
ctype_.parse(content_type);
|
||||
}
|
||||
|
||||
bool mail_body::save_html(const char* html, size_t len, string& out) const
|
||||
|
@ -202,9 +202,9 @@ const char* mail_message::get_header_value(const char* name) const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mail_message& mail_message::set_body(const mail_body* body)
|
||||
mail_message& mail_message::set_body(const mail_body& body)
|
||||
{
|
||||
body_ = body;
|
||||
body_ = &body;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,8 @@
|
||||
|
||||
namespace acl {
|
||||
|
||||
smtp_client::smtp_client(const char* addr, int conn_timeout, int rw_timeout)
|
||||
smtp_client::smtp_client(const char* addr, int conn_timeout /* = 60 */,
|
||||
int rw_timeout /* = 60 */)
|
||||
{
|
||||
addr_ = acl_mystrdup(addr);
|
||||
conn_timeout_ = conn_timeout;
|
||||
@ -18,24 +19,14 @@ smtp_client::smtp_client(const char* addr, int conn_timeout, int rw_timeout)
|
||||
client_ = NULL;
|
||||
|
||||
ehlo_ = true;
|
||||
reuse_ = false;
|
||||
ssl_conf_ = NULL;
|
||||
}
|
||||
|
||||
smtp_client::~smtp_client()
|
||||
{
|
||||
acl_myfree(addr_);
|
||||
|
||||
if (client_)
|
||||
{
|
||||
// 将 SMTP_CLIENT 对象的流置空,以避免内部再次释放,
|
||||
// 因为该流对象会在下面 stream_.close() 时被释放
|
||||
client_->conn = NULL;
|
||||
smtp_close(client_);
|
||||
}
|
||||
|
||||
// 当 socket 流对象打开着,则关闭之,同时将依附于其的 SSL 对象释放
|
||||
if (stream_.opened())
|
||||
stream_.close();
|
||||
close();
|
||||
}
|
||||
|
||||
smtp_client& smtp_client::set_ssl(polarssl_conf* ssl_conf)
|
||||
@ -56,6 +47,32 @@ const char* smtp_client::get_status() const
|
||||
|
||||
bool smtp_client::send(const mail_message& message,
|
||||
const char* email /* = NULL */)
|
||||
{
|
||||
// 发送 SMTP 邮件信封过程
|
||||
if (send_envelope(message) == false)
|
||||
return false;
|
||||
|
||||
// 优先使用参数给出的邮件文件,然后才是 message 中自动生成的邮件文件
|
||||
if (email == NULL)
|
||||
email = message.get_email();
|
||||
|
||||
// 如果没有可发送的邮件文件,则认为调用者想通过 write 等接口直接发送数据
|
||||
if (email == NULL)
|
||||
return true;
|
||||
|
||||
// 发送 DATA 命令
|
||||
if (data_begin() == false)
|
||||
return false;
|
||||
|
||||
// 发送邮件
|
||||
if (send_email(email) == false)
|
||||
return false;
|
||||
|
||||
// 发送 DATA 结束符
|
||||
return data_end();
|
||||
}
|
||||
|
||||
bool smtp_client::send_envelope(const mail_message& message)
|
||||
{
|
||||
if (open() == false)
|
||||
return false;
|
||||
@ -63,31 +80,21 @@ bool smtp_client::send(const mail_message& message,
|
||||
return false;
|
||||
if (greet() == false)
|
||||
return false;
|
||||
if (!auth_login(message.get_auth_user(), message.get_auth_pass()))
|
||||
|
||||
const char* user = message.get_auth_user();
|
||||
const char* pass = message.get_auth_pass();
|
||||
if (user && pass && auth_login(user, pass) == false)
|
||||
return false;
|
||||
|
||||
const rfc822_addr* from = message.get_from();
|
||||
if (from == NULL || from->addr == NULL)
|
||||
if (from == NULL)
|
||||
{
|
||||
logger_error("from null");
|
||||
return false;
|
||||
}
|
||||
if (mail_from(from->addr) == false)
|
||||
return false;
|
||||
if (to_recipients(message.get_recipients()) == false)
|
||||
return false;
|
||||
if (email != NULL)
|
||||
{
|
||||
if (send_email(email) == false)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
email = message.get_email();
|
||||
if (email != NULL)
|
||||
{
|
||||
if (send_email(email) == false)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return to_recipients(message.get_recipients());
|
||||
}
|
||||
|
||||
bool smtp_client::open()
|
||||
@ -96,9 +103,12 @@ bool smtp_client::open()
|
||||
{
|
||||
acl_assert(client_ != NULL);
|
||||
acl_assert(client_->conn == stream_.get_vstream());
|
||||
reuse_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
reuse_ = false;
|
||||
|
||||
client_ = smtp_open(addr_, conn_timeout_, rw_timeout_, 1024);
|
||||
if (client_ == NULL)
|
||||
{
|
||||
@ -106,9 +116,10 @@ bool smtp_client::open()
|
||||
return false;
|
||||
}
|
||||
|
||||
// 打开流对象
|
||||
// 打开流对象,只所以使用 stream_ 主要为了使用 SSL 通信
|
||||
stream_.open(client_->conn);
|
||||
|
||||
// 如果设置了 SSL 通信方式,则需要打开 SSL 通信接口
|
||||
if (ssl_conf_)
|
||||
{
|
||||
polarssl_io* ssl = new polarssl_io(*ssl_conf_, false);
|
||||
@ -119,11 +130,34 @@ bool smtp_client::open()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void smtp_client::close()
|
||||
{
|
||||
if (client_)
|
||||
{
|
||||
// 将 SMTP_CLIENT 对象的流置空,以避免内部再次释放,
|
||||
// 因为该流对象会在下面 stream_.close() 时被释放
|
||||
client_->conn = NULL;
|
||||
smtp_close(client_);
|
||||
client_ = NULL;
|
||||
}
|
||||
|
||||
// 当 socket 流对象打开着,则关闭之,同时将依附于其的 SSL 对象释放
|
||||
if (stream_.opened())
|
||||
stream_.close();
|
||||
|
||||
// 重置连接是否被重用的状态
|
||||
reuse_ = false;
|
||||
}
|
||||
|
||||
bool smtp_client::get_banner()
|
||||
{
|
||||
// 如果是同一个连接被使用,则不必再获得服务端的欢迎信息
|
||||
if (reuse_)
|
||||
return true;
|
||||
return smtp_get_banner(client_) == 0 ? true : false;
|
||||
}
|
||||
|
||||
@ -173,7 +207,7 @@ bool smtp_client::to_recipients(const std::vector<rfc822_addr*>& recipients)
|
||||
std::vector<rfc822_addr*>::const_iterator cit;
|
||||
for (cit = recipients.begin(); cit != recipients.end(); ++cit)
|
||||
{
|
||||
if ((*cit)->addr && rcpt_to((*cit)->addr) != 0)
|
||||
if ((*cit)->addr && rcpt_to((*cit)->addr) == false)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user