1. 程式人生 > >linux下用C編寫的基於smtp的帶附件郵件傳送程式

linux下用C編寫的基於smtp的帶附件郵件傳送程式

         今天做了一個簡單的stmp郵件傳送的客戶端demo,可以支援帶附件傳送,希望將實現分享一下, 目前測試環境是公司的內部郵箱, 

有gmail郵箱測試沒有成功, 可能gmail郵箱需要ssl加密,後續再進行完善吧, 這個demo實現的非常簡單的阻塞的傳送傳送郵件, 在後續的工作中需要

改成非阻塞的方式, 原理就是這樣的。 你可以在網上stmp的原理,網上資料很多,在這裡就不羅嗦了,本人水平有限, 如有問題,大家可以相互交流,共同

進步。

下面是原始碼:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#include <netdb.h>


#define TEST_IMG     ("test.jpg")
static char base64_table[64] =
{
	'A', 'B', 'C', 'D', 'E', 'F', 'G',
	'H', 'I', 'J', 'K', 'L', 'M', 'N',
	'O', 'P', 'Q', 'R', 'S', 'T',
	'U', 'V', 'W', 'X', 'Y', 'Z',
	'a', 'b', 'c', 'd', 'e', 'f', 'g',
	'h', 'i', 'j', 'k', 'l', 'm', 'n',
	'o', 'p', 'q', 'r', 's', 't',
	'u', 'v', 'w', 'x', 'y', 'z',
	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
	'+', '/'
};


int base64_encode(unsigned char *buf, int nLen, char *pOutBuf, int nBufSize);

void sendemail(char *stmpServer, char *body);
int open_socket(struct sockaddr *addr);

int main()
{
    FILE * fp = NULL;
    char buf[128] = {0};
    char outbuf[256] = {0};
    char *body = NULL;
    char email[] = "smtp.**.com";
#if 0
    char body[] = "From: \"********\"<****@qq.com>\r\n"
        "To:  \"horst\"<>\r\n"
        "Subject: Hello\r\n\r\n"
        "this is a test!\n"
        "good bye!"
        "MIME-Version:1.0\r\n"
        "Content-Type:multipart/mixed;boundary=\"---=_NextPart_000_0050_01C\"\r\n"
        "Subject:=?gb2312?B?TU1NRdCt0unLtcP308q8/g==?=\r\n";
#endif
    char bodyHead[] = "From: \"****\"<***@**.com>\r\n"
        "To:  \"**\"<**>\r\n"
        "MIME-Version:1.0\r\n"
        "Content-Type:multipart/mixed;boundary=\"---=_NextPart_000_0050_01C\"\r\n"
        "Subject:test\r\n"
        "\r\n"
        "-----=_NextPart_000_0050_01C\r\n"
        "Content-Type:text/plain;charset=\"gb2312\"\r\n"
        "\r\n"
        "hello \r\n"
        "-----=_NextPart_000_0050_01C\r\n"
        "\r\n\r\n"
        "Content-Type:application/octet-stream;name=\"test.jpg\"\r\n"
        "Content-Transfer-Encoding:base64\r\n"
        "Content-Disposion:attachment;filename=\"test.jpg\""
        "\r\n\r\n";
        
    char bodyend[] = "\r\n-----=_NextPart_000_0050_01C\r\n";

    body = malloc(8 * 1024 * 1024);
    if(NULL == body)
    {
        perror("malloc(): ");
        return -1;
    }

    memset(body, 0x0, 8*1024*1024);

    sprintf(body, bodyHead);
    
    fp = fopen(TEST_IMG, "rb");
    if(fp == NULL)
    {
        perror("fopen(): ");
        return -1;
    }

    memset(buf, 0x0, 128);
    memset(outbuf, 0x0, 256);
    int len = 0;
    char *ptr = NULL;
    ptr = body + strlen(body);
    while((len = fread(buf, sizeof(char), 60, fp)) > 0)
    {
        base64_encode(buf, len, outbuf, sizeof(outbuf));
        len = sprintf(outbuf, "%s\r\n", outbuf);
        printf("len :  %d\n", len);
        sprintf(ptr, outbuf);
        memset(buf, 0x0, 128);
        memset(outbuf, 0x0, 256);
        ptr += len;
    }

    sprintf(ptr, "\r\n\r\n");
    ptr += strlen("\r\n\r\n");
    sprintf(ptr, bodyend);

    sendemail(email, body);

    fclose(fp);
    free(body);

    return 0;




}

int base64_encode(unsigned char* pBase64, int nLen, char* pOutBuf, int nBufSize)
{
	int i = 0;
	int j = 0;
	int nOutStrLen = 0;

	/* nOutStrLen does not contain null terminator. */
	nOutStrLen = nLen / 3 * 4 + (0 == (nLen % 3) ? 0 : 4);
	if ( pOutBuf && nOutStrLen < nBufSize )
	{
		char cTmp = 0;
		for ( i = 0, j = 0; i < nLen; i += 3, j += 4 )
		{
			/* the first character: from the first byte. */
			pOutBuf[j] = base64_table[pBase64[i] >> 2];

			/* the second character: from the first & second byte. */
			cTmp = (char)((pBase64[i] & 0x3) << 4);
			if ( i + 1 < nLen )
			{
				cTmp |= ((pBase64[i + 1] & 0xf0) >> 4);
			}
			pOutBuf[j+1] = base64_table[(int)cTmp];

			/* the third character: from the second & third byte. */
			cTmp = '=';
			if ( i + 1 < nLen )
			{
				cTmp = (char)((pBase64[i + 1] & 0xf) << 2);
				if ( i + 2 < nLen )
				{
					cTmp |= (pBase64[i + 2] >> 6);
				}
				cTmp = base64_table[(int)cTmp];
			}
			pOutBuf[j + 2] = cTmp;

			/* the fourth character: from the third byte. */
			cTmp = '=';
			if ( i + 2 < nLen )
			{
				cTmp = base64_table[pBase64[i + 2] & 0x3f];
			}
			pOutBuf[j + 3] = cTmp;
		}

		pOutBuf[j] = '\0';
	}

	return nOutStrLen + 1;
}

/** 
 * @func  sendemail
 * @brief send email in blocking-mode
 * @param smtpServer 
 * @param body 
 */
void sendemail(char *smtpServer, char *body)
{
    int sockfd = 0;
    struct sockaddr_in their_addr = {0};
    char buf[1500] = {0};
    char rbuf[1500] = {0};
    char login[128] = {0};
    char pass[128] = {0};
    struct hostent *host = NULL;

    if((host = gethostbyname(smtpServer))==NULL)/*取得主機IP地址*/
    {
        fprintf(stderr,"Gethostname error, %s\n", strerror(errno));
        exit(1);
    }


    memset(&their_addr, 0, sizeof(their_addr));
    their_addr.sin_family = AF_INET;
    their_addr.sin_port = htons(25);
    their_addr.sin_addr = *((struct in_addr *)host->h_addr);

    sockfd = open_socket((struct sockaddr *)&their_addr);

    memset(rbuf, 0, 1500);

    while(recv(sockfd, rbuf, 1500, 0) == 0)
    {
        printf("reconnect..\n");

        close(sockfd);
        sleep(2);
        sockfd = open_socket((struct sockaddr *)&their_addr);

        memset(rbuf, 0, 1500);
    }

    printf("%s\n", rbuf);

    /* EHLO */

    memset(buf, 0, 1500);
    sprintf(buf, "EHLO abcdefg-PC\r\n");

    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);

    recv(sockfd, rbuf, 1500, 0);

    printf("%s\n", rbuf);

    /*AUTH LOGIN  */
    memset(buf, 0, 1500);
    sprintf(buf, "AUTH LOGIN\r\n");
    send(sockfd, buf, strlen(buf), 0);

    printf("%s\n", buf);

    memset(rbuf, 0, 1500);

    recv(sockfd, rbuf, 1500, 0);

    printf("%s\n", rbuf);

    /* USER */
    memset(buf, 0, 1500);

    sprintf(buf, "********");
    memset(login, 0, 128);

    base64_encode(buf, strlen(buf), login, 128);                   /* base64 */

    sprintf(buf, "%s\r\n", login);
    send(sockfd, buf, strlen(buf), 0);
    printf("%s\n", buf);

    memset(rbuf, 0, 1500);

    recv(sockfd, rbuf, 1500, 0);
    printf("%s\n", rbuf);

    /* PASSWORD */
    memset(buf, 0, 1500);
    sprintf(buf, "******");
    memset(pass, 0, 128);

    base64_encode(buf, strlen(buf), pass, 128);
    memset(buf, 0, 1500);
    sprintf(buf, "%s\r\n", pass);
    send(sockfd, buf, strlen(buf), 0);

    printf("%s, %d\n", buf, __LINE__);

    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    printf("%s, %d\n", rbuf, __LINE__);

    /* MAIL FROM */

    memset(buf, 0, 1500);
    sprintf(buf, "MAIL FROM: <****@**.com>\r\n");
    send(sockfd, buf, strlen(buf), 0);

    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);

    printf("%s\n", rbuf);

    /* rcpt to 第一個收件人 */
    sprintf(buf, "RCPT TO:<***@***.com>\r\n");
    send(sockfd, buf, strlen(buf), 0);

    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);

    printf("%s\n", rbuf);

    /* DATA email connext ready  */

    sprintf(buf, "DATA\r\n");
    send(sockfd, buf, strlen(buf), 0);

    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    printf("%s\n", rbuf);

    /* send email connext \r\n.\r\n end*/

    sprintf(buf, "%s\r\n.\r\n", body);

    send(sockfd, buf, strlen(buf), 0);

    memset(rbuf, 0, 1500);

    recv(sockfd, rbuf, 1500, 0);
    printf("%s\n", rbuf);

    /* QUIT */

    sprintf(buf, "QUIT\r\n");
    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);

    recv(sockfd, rbuf, 1500, 0);
    printf("%s\n", rbuf);

    return ;

}

int open_socket(struct sockaddr *addr)
{
    int sockfd = 0;
    sockfd = socket(PF_INET, SOCK_STREAM, 0);

    if(sockfd < 0)
    {
        fprintf(stderr, "Open sockfd(TCP ) error!\n");
        exit(-1);
    }

    if(connect(sockfd, addr, sizeof(struct sockaddr)) < 0)
    {
        close(sockfd);

        fprintf(stderr, "Connect sockfd(TCP ) error!\n");
        exit(-1);
    }

    return sockfd;

}

 

相關推薦

linuxC編寫基於smtp附件郵件傳送程式

         今天做了一個簡單的stmp郵件傳送的客戶端demo,可以支援帶附件傳送,希望將實現分享一下, 目前測試環境是公司的內部郵箱,  有gmail郵箱測試沒有成功, 可能gmail郵箱需要ssl加密,後續再進行完善吧, 這個demo實現的非常簡單的阻塞的傳送傳送

linuxC編寫ftp客戶端

這是一個大作業,要求能夠模擬ftp協議,實現一個ftp客戶端,然後要求能夠實現相應的功能,主要是能夠實現ls,pwd,cwd(cd),put和get功能。然後是在被動模式下來實現這些功能。那麼首先我們需要對ftp協議有一個具體的瞭解,然後才能夠自己實現這個功能。 FTP

linuxvim編寫C/C++單個源程式的基本方法

在Linux下可以用於程式設計的工具實在是太多了,我比較喜歡的是Kdevelop,今天又學了下在終端直接用vim編寫簡單C/C++程式的方法。這樣貌似更方便些。 一、在終端直接用vim編寫C程式 在某路徑下開啟一個終端,或開啟終端後進入你想存放原始檔的路徑,然後 [[em

編寫LinuxC語言訪問MySQL資料庫的程式

  在編寫這個程式的時候我和同學費了很大的力氣特別是在編譯的時候,下面我就把自己編譯的經驗給大家分享一下,希望大家能少走一些彎路。     我自己裝了mysql-5.0.41-linux-i686-glibc23.tar.gz 安裝部分就不說了!

LinuxC獲取當前時間

time() 使用 ble timespec -1 ber 區間 本地 指向 Linux下用C獲取當前時間,具體如下: 代碼(可以把clock_gettime換成time(NULL)) ? 1 2 3 4 5 6 7 8 9 10 void getN

LinuxC實現域名到IP的轉換(域名解析)

只需呼叫一個函式即可gethostbyname(),gethostbyname()返回對應於給定主機名的包含主機名字和地址資訊的hostent結構指標。結構的宣告與gethostaddr()中一致。下面是函式原型: Windows平臺下 #include <winsock2.h>

Linuxc語言實現發送http請求 方式可以Get或者Post例程參考

sockaddr select sleep online 創建 線程終止 index -s lse [1].[代碼] Linux下用c語言實現發送http請求 方式可以Get或者Post 跳至 [1] ? 1 2 3 4 5 6 7 8 9 10 11 12 1

Linuxc語言實現傳送http請求 方式可以Get或者Post例程參考

[1].[程式碼] Linux下用c語言實現傳送http請求 方式可以Get或者Post 跳至 [1] ? 1 2

Linuxc語言實現傳送http請求

前言 在linux下,使用socket進行程式設計,需要到伺服器上進行獲取資料,伺服器使用的php程式設計,需要使用http的方式進行獲取資料。 程式碼 #include <stdio.h> #include <string.h&

在Centosc++編寫簡單程式並輸出

小白我使用的是VMware-Workstation虛擬機器建立的centos。苦於無法用來學習(裝逼),抽空學習瞭如何在linux系統下程式設計。有不對的地方歡迎各位大佬指出,謝謝。首先開啟centos

LinuxC實現串列埠讀寫

 http://hi.baidu.com/weiweisuo1986/item/b33200134ceaac6871d5e81d         之前要做一個和串列埠相關的專案,才認真研究了下串列埠,首先就是要實現串列埠和PC機的通訊。          串列埠的驅動一般不需要我們寫,都是很成熟的驅動

LinuxC獲取當前系統時間

#include   <time.h> time_t   time(time_t   calptr); 返回的是日曆時間,即國際標準時間公元1970年1月1日00   :   00   :   00以來經過的秒數。然後再呼叫 char   *ctime(const

LinuxC++實現通過程序名稱獲取程序ID

近期開發的系統功能涉及到程序之間的查詢、程序對程序的啟停操作。 在shell環境下,使用程序名稱查詢程序ID非常簡單,例如通過 ps -ef | grep "proc_name"來檢視名為“proc_name”程序, 也可以通過pidof "proc_name"來獲取程序

linuxC語言獲取本地時間

一個小專案需要以系統時間(精確到微秒)為變數建立檔名,在網上搜索資料,在stackoverflow上找到了需要的東西,記下來備用 #include <sys/time.h> #include <time.h> #include <stdio

LinuxC語言判斷程式是否已執行

通過程式名獲得程序號,然後和當前程式程序號做對比。 int isRunning() { int ret = 0; char sCurrPid[16] = {0}; spri

LinuxGCC自己寫個很簡單的小程式

最近研究LINUX,最近又搞了點GCC編譯玩玩,廢話不多,開始切入正題: 1:新建一個檔案 touch h.c 2:給h.c檔案寫程式碼: #include <stdio.h> int main(void) { printf("Hello,WT!"); retur

C# 附件郵件傳送(支援多附件

工作需要用到了多附件傳送功能,現在貼出來,有需要的共享一下。 //帶附件傳送,支援多個附件        public bool sendMailFile(string from, string to, string subject, string body,string

linux利用CC++ 語言調需要root權限的函數

編譯程序 註意 步驟 oot 登錄 調用 get bsp 屬於 1、setuid法(1)登錄root用戶,將程序設置成root:root所有者(等價於:登錄root用戶編譯程序)。也可直接將普通用戶加入root組中,那麽編譯程序不用來回切換用戶。(2)登錄root用戶設置程

LinuxC/C++開發基礎(編寫makefile、編譯C/C++、連結、可執行程式

本文重點介紹C/C++原始碼工程的編譯連結,編譯器gcc/g++的安裝配置略過... 1. 安裝配置gcc g++ 2. 建立檔案 test.h /test.c / file.h  / file.cpp  3. 編譯.o庫: gcc -c / g++ -c     連結生成靜

linux應用層C呼叫音訊驅動

static void audio_pause(void) {     int err;     if (alsa_can_pause) {         if ((err = snd_pcm_pause(alsa_handler, 1)) < 0)