久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

標題: 簡單電子郵件SMTP協議解析 [打印本頁]

作者: 51黑小牛    時間: 2016-4-10 20:22
標題: 簡單電子郵件SMTP協議解析
最近幾日學習了一下簡單電子郵件協議smtp的使用,并移植了smtp協議棧中的code,幾經折返,最終成功實現郵件的發送。

一、SMTP協議流程
首先通過計算機的telnet或者TCPIP調試工具來輸入命令。我是使用TCP調試工具進行的驗證。

1、SMTP服務器網絡地址
首先去163郵箱注冊一個用戶,然后在郵箱里面設置去掉SSL并開啟SMTP的3個選項。之后就可以使用了,
就163郵箱來說他的服務器是smtp.163.com。為了和程序一致所以需要轉換為IP地址。通過DNS可以知道他的IP地址映射。
這樣就獲得了一個IP地址
2、SMTP服務器端口
SMTP默認的端口是 port =25
3、會話
使用TCP連接連接這個IP地址和25端口,連接成功之后服務器會發回來一串數如下
220 163.com Anti-spam GT for Coremail System (163com[20141201])
然后需要發送helo xxx命令發送完畢 ,否則他會返回503 Error: send HELO/EHLO first   xxx可以是個任意的名字他會返回
250 OK
表示完成握手接下來就是用戶名和密碼的認證了。需要你主動發送認證請求發送命令
auth login空格+回車
334 dXNlcm5hbWU6
這是表示提示輸入用戶名,
dXNlcm5hbWU6這個是用base64加密的username,然后輸入你的xxx@163.com,同樣的也需要轉換為BASE64碼,之后
334 UGFzc3dvcmQ6
這是表示提示輸入密碼了。同樣的
UGFzc3dvcmQ6表示password了輸入密碼******轉換為BASE64代碼,之后
235 Authentication successful
返回這個之后表示認證成功了,接下來就是發件人和收件人的email地址,然后依次輸入

mail from: <wjw890912@163.com>  +回車

rcpt to: <wjw890912@163.com> +回車

服務器都會回復250 Mail OK 來確認。接下來就是郵件的標題和正文了,輸入之

data
From:PC
To:XX163
Subject:Test for Smtp

The PC sent e-mail to here pass the SMTP.


.

最后的一個點時必要的。必須要。最后輸入quit命令,就斷開連接退出了此次會話。一封電子郵件也就被發到了郵箱中了。可以在郵箱中看到發送的內容。


二、代碼移植和修改

已經通過TCP工具進行了模擬,只要按照這個流程就可以用程序把人發的變成自動發。首先gitHub拿到代碼后找到smtp.c和smtp.h倆文件。加入到project 中設置C/C++ 中include paths 。 找到API接口重寫那個接口函數

    smtp_set_server_addr("220.181.12.18");//smtp.163.com
    smtp_set_auth("wjw890912@163.com","**************");//密碼和用戶名使用明文即可,系統自動轉碼
    smtp_send_mail("wjw890912@163.com", "wjw890912@163.com", "Reporter",  "The MCU sent e-mail to                                     here pass the  SMTP", my_smtp_result_fn,0 );

并添加一個回執函數my_smtp_result_fn
void my_smtp_result_fn(void *arg, u8_t smtp_result, u16_t srv_err, err_t err)
  {                       
   printf("mail (%p) sent with results: 0x%02x, 0x%04x, 0x%08x\n", arg, smtp_result, srv_err, err);
}
這是一個發送完成回執事件,發送完成后無論成功與否都會返回一個smtp_result,根據這個值應用程序作出相應的反應了。

最后編譯下載到目標板中執行

在debug的過程中發現這個程序并不能發出正確的郵件,于是對這個文件中的代碼稍微看了一下,
首先是程序的框架,首先他會建立一個描述
所謂的smtp session,用來記錄所有的有關系的項結構。然后調用TCP,創建一個用于連接的TCP PCB之后開始執行SMTP的狀態機。最后結束發送完成事件,非正常就是直接發送完成事件。所以關鍵是SMTP的裝態機。代碼如下
switch(s->state)
  {
  case(SMTP_NULL):
    /* wait for 220 */
    if (response_code == 220) {
      /* then send HELO */
      next_state = smtp_prepare_helo(s, &tx_buf_len, pcb);
    }
    break;
  case(SMTP_HELO):
    /* wait for 250 */
    if (response_code == 250) {
#if SMTP_SUPPORT_AUTH_PLAIN || SMTP_SUPPORT_AUTH_LOGIN
      /* then send AUTH or MAIL */
      next_state = smtp_prepare_auth_or_mail(s, &tx_buf_len);
    }
    break;
  case(SMTP_AUTH_LOGIN):
  case(SMTP_AUTH_PLAIN):
    /* wait for 235 */
    if (response_code == 235) {
#endif /* SMTP_SUPPORT_AUTH_PLAIN || SMTP_SUPPORT_AUTH_LOGIN */
      /* send MAIL */
      next_state = smtp_prepare_mail(s, &tx_buf_len);
    }
    break;
#if SMTP_SUPPORT_AUTH_LOGIN
  case(SMTP_AUTH_LOGIN_UNAME):
    /* wait for 334 Username */
    if (response_code == 334) {
      if (pbuf_strstr(s->p, SMTP_RESP_LOGIN_UNAME) != 0xFFFF) {
        /* send username */
        next_state = smtp_prepare_auth_login_uname(s, &tx_buf_len);
      }
    }
    break;
  case(SMTP_AUTH_LOGIN_PASS):
    /* wait for 334 Password */
    if (response_code == 334) {
      if (pbuf_strstr(s->p, SMTP_RESP_LOGIN_PASS) != 0xFFFF) {
        /* send username */
        next_state = smtp_prepare_auth_login_pass(s, &tx_buf_len);
      }
    }
    break;
#endif /* SMTP_SUPPORT_AUTH_LOGIN */
  case(SMTP_MAIL):
    /* wait for 250 */
    if (response_code == 250) {
      /* send RCPT */
      next_state = smtp_prepare_rcpt(s, &tx_buf_len);
    }
    break;
  case(SMTP_RCPT):
    /* wait for 250 */
    if (response_code == 250) {
      /* send DATA */
      SMEMCPY(s->tx_buf, SMTP_CMD_DATA, SMTP_CMD_DATA_LEN);
      tx_buf_len = SMTP_CMD_DATA_LEN;
      next_state = SMTP_DATA;
    }
    break;
  case(SMTP_DATA):
    /* wait for 354 */
    if (response_code == 354) {
      /* send email header */
      next_state = smtp_prepare_header(s, &tx_buf_len);
    }
    break;
  case(SMTP_BODY):
    /* nothing to be done here, handled somewhere else */
    break;
  case(SMTP_QUIT):
    /* wait for 250 */
    if (response_code == 250) {
      /* send QUIT */
      next_state = smtp_prepare_quit(s, &tx_buf_len);
    }
    break;
  case(SMTP_CLOSED):
    /* nothing to do, wait for connection closed from server */
    return;


然后改成本地服務器進行模擬,發現流程是正常的但是系統打印的代碼是大寫,服務器不能識別,于是改成小寫
#define SMTP_CMD_AUTHLOGIN        "auth login \r\n"
#define SMTP_CMD_AUTHLOGIN_LEN    13
#define SMTP_CMD_MAIL_1           "mail from: <"
#define SMTP_CMD_MAIL_1_LEN       12
#define SMTP_CMD_MAIL_2           ">\r\n"
#define SMTP_CMD_MAIL_2_LEN       3
#define SMTP_CMD_RCPT_1           "rcpt to: <"
#define SMTP_CMD_RCPT_1_LEN       10
#define SMTP_CMD_RCPT_2           ">\r\n"
#define SMTP_CMD_RCPT_2_LEN       3
#define SMTP_CMD_DATA             "data\r\n"
#define SMTP_CMD_DATA_LEN         6
#define SMTP_CMD_HEADER_1         "From: <"
#define SMTP_CMD_HEADER_1_LEN     7
#define SMTP_CMD_HEADER_2         ">\r\nTo: <"
#define SMTP_CMD_HEADER_2_LEN     8
#define SMTP_CMD_HEADER_3         ">\r\nSubject: "
#define SMTP_CMD_HEADER_3_LEN     12
#define SMTP_CMD_HEADER_4         "\r\n\r\n"
#define SMTP_CMD_HEADER_4_LEN     4
#define SMTP_CMD_BODY_FINISHED    "\r\n.\r\n"
#define SMTP_CMD_BODY_FINISHED_LEN 5
#define SMTP_CMD_QUIT             "quit\r\n"
#define SMTP_CMD_QUIT_LEN         6
依次修改這些宏。
還有一個地方就是握手的回復上是250 OK而原作者寫的是auth 或者auth=,但是實際并不會返回這個而是OK,所以需要改成
#define SMTP_KEYWORD_AUTH_SP    "OK"

#define SMTP_AUTH_PARAM_LOGIN   "OK"
最后修改一下改為小寫即可
#define SMTP_CMD_EHLO_1           "helo ["
#define SMTP_CMD_EHLO_1_LEN       6
#define SMTP_CMD_EHLO_2           "]\r\n"
#define SMTP_CMD_EHLO_2_LEN       3
#define SMTP_CMD_AUTHPLAIN_1      "AUTH PLAIN "
#define SMTP_CMD_AUTHPLAIN_1_LEN  11
#define SMTP_CMD_AUTHPLAIN_2      "\r\n"
#define SMTP_CMD_AUTHPLAIN_2_LEN  2

并且關閉 A UTH PLAIN 開關#define SMTP_SUPPORT_AUTH_PLAIN   0

最后一件事就是把板子的IP地址調整為可以訪問外網的IP號段,否則防火墻會攔截這個試圖發送郵件的非法IP地址,導致發送失敗。我這里是0和254、253修改為0號段后就可以正常的發出郵件了!

最后的最后@163郵箱一天中有郵件限制。不能一直發,2秒發一封這樣發不到200封郵件就會被限制,并返回錯誤。此時程序依舊是正常運行的只是服務器會返回中止的代碼而已。

如果要做應用把函數的輸入參數改為const char *ptr,然后指向一個數組并在末尾加‘\0’就可以把內存引用出來作為信件內容發送出去。比如送出個采集到的溫度值什么的,即可向郵箱完成一個小報告了。







作者: jjwangxu2008    時間: 2018-9-20 18:03
神奇的 東西!。。。。




歡迎光臨 (http://m.zg4o1577.cn/bbs/) Powered by Discuz! X3.1
主站蜘蛛池模板: a级片在线 | 欧美日韩精品一区二区在线播放 | 亚洲精品911 | 在线视频福利 | 91综合在线 | 欧美一级做性受免费大片免费 | 十八岁毛片 | 夜夜操夜夜操 | 国产欧美综合一区二区三区 | 999毛片| 一区二区三区精品 | 国产一区中文字幕 | 91tv国产成人福利 | 久久久婷婷| 一区视频在线 | www在线播放 | 黄色a视频 | 日韩一区三区 | 黄色片视频网站 | 水蜜桃一区二区 | 亚洲三级视频 | 黄色片免费在线观看 | 亚洲成人精品在线观看 | 精品久久久一区二区 | 97中文字幕 | 国产黄色录像 | 国产成人综合视频 | 国产欧美在线观看 | 91亚洲精品在线 | 99久久综合 | 亚洲国产成人精品久久 | 亚洲第一色 | 日韩黄色在线视频 | 免费在线观看黄 | 操欧美女人 | 成人做受黄大片 | av黄| 女人高潮特级毛片 | 日韩影音| 精品免费在线 | 99精品久久 |