- UID
- 1
- 精华
- 积分
- 76361
- 威望
- 点
- 宅币
- 个
- 贡献
- 次
- 宅之契约
- 份
- 最后登录
- 1970-1-1
- 在线时间
- 小时
|
呼。。终于完成了。
有关的内容大家可以参考我用Java写的轻量级电子邮件类smtpmail
其实这个C语言版的也差不多。区别在于,这个不需要自己保存数字签名文件,它反正就这么就能用。
效果图:
下面是通过SMTP和服务器交互的内容。想看?回帖后才能看到。为了写这个东西,我需要解决以下三个问题:
写好它以后,大家可以看看我的DEMO,使用我定义的接口进行SMTP协议邮件发送过程。这用起来还是非常方便的。- #include<stdio.h>
- #include<WinSock2.h>
- #include"smtpmail.h"
- #define DEMO_SERVER "smtp.qq.com",465
- #define DEMO_ACCOUNT "username","password"
- #define DEMO_FROMTO "username@qq.com","receiver@qq.com"
- //=============================================================================
- //函数:SendTestMail
- //描述:测试函数,展示发送邮件
- //-----------------------------------------------------------------------------
- sm_exception_t SendTestMail()
- {
- return sm_SendTextMail(sm_SSL,DEMO_SERVER,DEMO_ACCOUNT,DEMO_FROMTO,
- "这是测试邮件,来自smtpmail",
- "这是测试邮件的内容。");
- }
- //=============================================================================
- //函数:SendTestMailWithAttachment
- //描述:测试函数,展示发送带附件的邮件
- //-----------------------------------------------------------------------------
- sm_exception_t SendTestMailWithAttachment()
- {
- smtpmail_t sm;
- sm_exception_t ex;
- FILE*fp = NULL;
- sm_Init(&sm, sm_SSL);
- ex = sm_CatchException(&sm);
- if(ex)
- {
- sm_Cleanup(&sm);
- if(fp)
- fclose(fp);
- return ex;
- }
- sm_StartSendMail(&sm,DEMO_SERVER,DEMO_ACCOUNT,DEMO_FROMTO,
- "这是测试邮件,来自smtpmail,测试附件",
- sm_false);
- fp = fopen("attachment.gif","rb");
- sm_SendAttachment(&sm, "image/gif", fp, "name", "filename.gif");
- fclose(fp);fp=NULL;
- sm_StartSendPlainText(&sm);
- sm_SendPlainText(&sm, "这个邮件有一个GIF附件。");
- sm_EndSendPlainText(&sm);
- sm_FinishSendMail(&sm);
- sm_Cleanup(&sm);
- return sme_OK;
- }
- int main(int argc,char**argv)
- {
- # ifdef _MSC_VER
- {
- WSADATA wsaData;
- WSAStartup(WINSOCK_VERSION,&wsaData);
- }
- # endif // _MSC_VER
-
- fputs(sm_GetExceptionString(SendTestMail()),stderr);
- fputs(sm_GetExceptionString(SendTestMailWithAttachment()),stderr);
- return 0;
- }
复制代码
参考资料:
http://www.0xaa55.com/thread-1212-1-1.html
http://www.0xaa55.com/thread-1671-1-1.html
http://www.0xaa55.com/thread-1676-1-1.html
RFC 2821 (SMTP)
RFC 3207 (STARTTLS)
RFC 6409 (Port 587)
https://en.wikipedia.org/wiki/SMTPS
完整的代码:
smtpmail.h:- //=============================================================================
- //作者:0xAA55
- //作者网站:http://www.0xaa55.com/
- //本源码完全免费开放,大家可以随意拿去使用、修改、用于任何用途。
- //但是,由于本源码带来的任何损失,均与本作者无关。请保留此信息。
- //-----------------------------------------------------------------------------
- #ifndef _SMTP_MAIL_SENDER_
- #define _SMTP_MAIL_SENDER_
- #include<stdint.h>
- #include<setjmp.h>
- #include<Winsock2.h>
- #include<openssl/ssl.h>
- typedef enum
- {
- sm_false = 0,
- sm_true
- }sm_bool_t,*sm_bool_p;
- //=============================================================================
- //smtpmail的异常号码。用于追踪错误。
- typedef enum
- {
- sme_OK = 0, //没错
- sme_InvalidParam, //参数错误
- sme_NoEnoughMemory, //内存不足
- sme_ServerNotFound, //没找到服务器
- sme_InitSSLFailed, //初始化OpenSSL失败
- sme_SSLHandShakeErr, //OpenSSL握手失败
- sme_ConnectFail, //连接失败
- sme_SendFail, //发送失败
- sme_RecvFail, //接收失败
- sme_IncorrectData, //接收到了奇怪的数据
- sme_BadStatusCode, //服务器返回不好的状态码,不能再合作下去了
- sme_STARTTLS_Failed, //服务器不支持STARTTLS,但是用户要求必须支持
- sme_LoginFailed, //登录失败,错误的用户名和密码
- sme_SetFromToError, //设置收件人和发件人失败
- sme_SendMailFail, //最后服务器返回“发送邮件失败”
- sme_ReadFileError, //无法读取文件(无法发送附件)
- }sm_exception_t,*sm_exception_p;
- //=============================================================================
- //加密方式
- typedef enum
- {
- sm_Plain = 0, //发送明文,不加密
- sm_STARTTLS_Or_Plain, //明文连接,如果服务器支持STARTTLS就加密,否则发送明文
- sm_STARTTLS, //明文连接,服务器必须支持STARTTLS否则失败
- sm_SSL //SSL加密
- }sm_sectype_t,*sm_sectype_p;
- typedef struct smtpmail_s smtpmail_t,*smtpmail_p;
- typedef void(*Send_f)(smtpmail_p,const void*pBuf,size_t);
- typedef size_t(*Recv_f)(smtpmail_p,void*pBuf,size_t);
- #define MaxLine 255 /* 假定从服务器返回的字符串每行最大字符数 */
- struct smtpmail_s
- {
- //传输工具
- SOCKET Socket;
- Send_f pfnSend;
- Recv_f pfnRecv;
- //安全模式
- sm_sectype_t SecureMode;
- SSL_CTX *pCTX;
- SSL *pSSL;
- //接收数据缓冲区
- char RecvBuf[MaxLine + 1];//添加一个行结尾
- size_t cbRecv;
- char szSeparator[MaxLine + 1];//不同MIME块之间的分隔行
- size_t cbSeparator;//分隔行的长度
- //最后状态
- uint32_t uLastStatus;
- char pLastRecvStr[MaxLine + 1];
- //错误处理,这个必须设置
- jmp_buf OnError;
- };
- //=============================================================================
- //函数:sm_Init
- //描述:初始化邮件发送器
- //-----------------------------------------------------------------------------
- void sm_Init
- (
- smtpmail_p ps,
- sm_sectype_t SecureMode//安全模式
- );
- //=============================================================================
- //函数:sm_CatchException
- //描述:捕获异常处理。必须在调用sm_Init后直接使用。
- // 一旦出现异常,程序将从这里返回。切记返回完后调用sm_Cleanup进行清理。
- //-----------------------------------------------------------------------------
- #define sm_CatchException(ps) (sm_exception_t)setjmp((ps)->OnError)
- //=============================================================================
- //函数:sm_StartSendMail
- //描述:开始发送正文。调用前必须先调用sm_CatchException。
- //-----------------------------------------------------------------------------
- void sm_StartSendMail
- (
- smtpmail_p ps,
- const char *pszServerAddr, //服务器地址,如“smtp.qq.com”
- uint16_t uPort, //服务器端口,如“465”
- const char *pUsername, //用户名,如[QQ号]
- const char *pPassword, //密码,如[QQ密码]
- const char *pMailFrom, //发件人,如QQ号@qq.com
- const char *pRcptTo, //收件人,如xxx@xx.com
- const char *pSubject, //主题,如“测试邮件”
- sm_bool_t bHaveAttachment //是否打算发送附件
- );
- //=============================================================================
- //函数:sm_StartSendMimeData
- // sm_StartSendMimeDataAsAttachment
- // sm_SendMimeData
- // sm_SendTextMimeData
- // sm_EndSendMimeData
- //描述:发送MIME内容。
- //有关MIME类型的资料:
- //http://www.sitepoint.com/web-foundations/mime-types-complete-list/
- //-----------------------------------------------------------------------------
- void sm_StartSendMimeData(smtpmail_p ps,const char*pszMimeType);
- void sm_StartSendMimeDataAsAttachment
- (
- smtpmail_p ps,
- const char*pszMimeType,
- const char*pszName, //附件名
- const char*pszFilename //附件文件名
- );
- void sm_SendMimeData(smtpmail_p ps,const void*pszData,size_t cbData);
- void sm_SendTextMimeData(smtpmail_p ps,const char*pszText);
- void sm_EndSendMimeData(smtpmail_p ps);
- #define sm_StartSendPlainText(ps) sm_StartSendMimeData(ps, "text/plain")
- #define sm_SendPlainText(ps, pszText) sm_SendTextMimeData(ps, pszText)
- #define sm_EndSendPlainText(ps) sm_EndSendMimeData(ps)
- #define sm_StartSendHTML(ps) sm_StartSendMimeData(ps, "text/html")
- #define sm_SendHTML(ps,pszText) sm_SendMimeData(ps, pszText)
- #define sm_EndSendHTML(ps) sm_EndSendMimeData(ps)
- //=============================================================================
- //函数:sm_SendAttachment
- //描述:发送附件
- //-----------------------------------------------------------------------------
- void sm_SendAttachment
- (
- smtpmail_p ps,
- const char*pszMimeType, //MIME类型
- FILE*fp, //已经打开的文件
- const char*pName, //附件名
- const char*pFilename //文件名,不含路径
- );
- //=============================================================================
- //函数:sm_FinishSendMail
- //描述:完成邮件的发送(最后一步)
- //-----------------------------------------------------------------------------
- void sm_FinishSendMail(smtpmail_p ps);
- //=============================================================================
- //函数:sm_Cleanup
- //描述:用完smtpmail后,清理内存。
- //-----------------------------------------------------------------------------
- void sm_Cleanup(smtpmail_p ps);
- //=============================================================================
- //函数:sm_SendTextMail
- //描述:一步完成——发送纯文本邮件
- //-----------------------------------------------------------------------------
- sm_exception_t sm_SendTextMail
- (
- sm_sectype_t SecureMode, //安全模式
- const char *pszServerAddr, //服务器地址,如“smtp.qq.com”
- uint16_t uPort, //服务器端口,如“465”
- const char *pUsername, //用户名,如[QQ号]
- const char *pPassword, //密码,如[QQ密码]
- const char *pMailFrom, //发件人,如QQ号@qq.com
- const char *pRcptTo, //收件人,如xxx@xx.com
- const char *pSubject, //主题,如“测试邮件”
- const char *pText //纯文本内容
- );
- //=============================================================================
- //函数:sm_GetExceptionString
- //描述:取得用于描述异常的字符串
- //-----------------------------------------------------------------------------
- char*sm_GetExceptionString(sm_exception_t e);
- #endif // !_SMTP_MAIL_SENDER_
复制代码 smtpmail.c:回帖后可见。SRC:
smtpmail.7z
(9.22 KB, 下载次数: 74)
不过由于论坛上传附件大小限制的关系,这个附件只包含了核心的代码。而OpenSSL则并没有包含在里面,所以不能编译通过。
完整的源码包请回帖后查看并下载。 |
|