";
const char
*userID="watashi";
const char *passwd="uso800";
const int
port=587;
/* Import
Library: Link with ws2_32.lib */
#include <stdio.h>
#include
<string.h>
#include <winsock2.h>
/*ソケットsに文字列データdataを送信する関数*/
void sendData(SOCKET s, char
*data)
{
send(s,data,strlen(data),0);
}
/*ソケットsからバッファサイズbuffsizeのデータバッファdatabuffに
データを受け取る関数 返す値は取得バイト数*/
int
receiveData(SOCKET s, char *databuff, int
buffsize)
{
char
*p=databuff;
int i;
for
(i=0;i<buffsize;i++) *p++=0;
return
recv(s,databuff,buffsize,0);
}
/**************** for printing information HEAD
************************/
#ifdef REQUEST_INFO
void
printWinsockInfo(WSADATA *wsaData)
{
union
{
short int
s;
unsigned char
c[2];
} v,hv;
if
(wsaData==NULL) return;
v.s=wsaData->wVersion;
hv.s=wsaData->wHighVersion;
printf("== winsock
information ==\n");
printf("winsock
version = %d.%d\n",v.c[0],v.c[1]);
printf("winsock HighVer =
%d.%d\n",hv.c[0],hv.c[1]);
printf("Description =
%s\n",wsaData->szDescription);
printf("SystemStatus = %s\n"
,wsaData->szSystemStatus);
printf("Max
Sockets = %d\n"
,wsaData->iMaxSockets);
printf("Max UDP byte size
= %d\n" ,wsaData->iMaxUdpDg);
printf("\n");
}
void printServerInfo(LPHOSTENT
lpHost)
{
int i;
if
(lpHost==NULL) return;
printf("== server information
==\n");
printf("host
name = %s\n" ,
lpHost->h_name);
printf("address type
= %d\n" , lpHost->h_addrtype); /*AF_INETは2*/
printf("address length = %d\n" ,
lpHost->h_length);
for(i = 0 ;
lpHost->h_aliases[i] ; i++)
{
printf("aliases = %s\n" ,
lpHost->h_aliases[i]);
}
for(i = 0 ; lpHost->h_addr_list[i] ;
i++) {
IN_ADDR
*ip;
ip = (IN_ADDR
*)lpHost->h_addr_list[i];
printf("IP address = %s\n" ,
inet_ntoa(*ip));
}
printf("\n");
}
void printServiceInfo(LPSERVENT
lpServ)
{
int i;
if
(lpServ==NULL) return;
printf("== service
information ==\n");
printf("service name = %s\n" ,
lpServ->s_name);
for(i = 0 ;
lpServ->s_aliases[i] ; i++)
{
printf("aliases = %s\n" ,
lpServ->s_aliases[i]);
}
printf("port number = %d\n" ,
lpServ->s_port);
printf("protocol = %s\n" ,
lpServ->s_proto);
printf("\n");
}
void
printPortInfo(int port)
{
printf("== port number
information ==\n");
printf("port number = %d\n" ,
ntohs((short)port));
/*ntohsはホストバイトオーダーに戻す関数*/
printf("\n");
}
#endif
/**************** for printing
information TAIL ************************/
/************************************************************
ソケットをオープンし,目的のサーバのポートに接続する
server:
サーバの名前(ドメイン名,ドメインを省略してはいけない)
例えばaaaa.tokyo-ct.ac.jp
servicename:"smtp"とか"http"などのサービスの名前,
次のところに名前の一覧がある
Windowsシステムのsystem32\drivers\etc\services
service:
サービスのポート番号,smtpなら25,httpなら80など
この情報は,servicenameが不明の場合に必要なだけで,
通常は使われない
不成功ならINVALID_SOCKETを返す
*************************************************************/
SOCKET
connectSocket(const char *server, char *servicename, short int
service)
{
WSADATA wsaData;
/*winsock*/
LPHOSTENT lpHost;
LPSERVENT lpServ;
SOCKET sock;
SOCKADDR_IN sockAddr;
int port;
/*ポート番号*/
int status;
/*winsockをver1.1で初期化を要求*/
status=WSAStartup(MAKEWORD(1, 1), &wsaData);
if
(status != 0) {
fprintf(stderr,"WSAStartup()
failed\n");
return
INVALID_SOCKET;
}
/*サーバ名からホストの情報を得る*/
lpHost =
gethostbyname(server);
if(lpHost == NULL)
{
fprintf(stderr,"server
name error\n");
WSACleanup();
return
INVALID_SOCKET;
}
/*サービス情報からポート番号取得*/
lpServ =
getservbyname(servicename, NULL);
if (lpServ ==
NULL) {
port=htons(service);
/*ホストバイトオーダーからネットワークバイトオーダー(ビッグエンディアン)に変換*/
} else
{
port=lpServ->s_port;
}
#ifdef REQUEST_INFO
/*情報要求がある場合(学習のため)*/
printWinsockInfo(&wsaData);
/*Winsocの情報表示*/
printServerInfo(lpHost);
/*サーバの情報表示*/
printServiceInfo(lpServ);
/*サービスの情報表示*/
printPortInfo(port);
/*ポート番号の情報表示*/
#endif
/*ソケットオープン*/
sock
= socket(PF_INET, SOCK_STREAM, 0);
if (sock ==
INVALID_SOCKET) {
fprintf(stderr,"socket()
error\n");
WSACleanup();
return
INVALID_SOCKET;
}
/*ソケット結合*/
sockAddr.sin_family = AF_INET;
sockAddr.sin_port =
port;
sockAddr.sin_addr =
*((LPIN_ADDR)*lpHost->h_addr_list);
status=connect(sock, (PSOCKADDR)&sockAddr,
sizeof(SOCKADDR_IN));
if (status)
{
fprintf(stderr,"connect()
error\n");
closesocket(sock);
WSACleanup();
return
INVALID_SOCKET;
}
return
sock;
}
#define sndBufSize
100*1024
#define rcvBufSize 1024
typedef struct
{
char sender[128];
/*送信者すなわち自分のメールアドレス*/
char
receiver[128]; /*送信先のメールアドレス*/
char subject[1024]; /*サブジェクト(件名)*/
char body[sndBufSize]; /*メール本体*/
} mail_t;
//mime変換のためのテーブル
0123456789012345678901234567890123456789012345678901234567890123
const
char
MimeEncodeTable[70]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//文字列intext(normal)を文字列otext(mime
encoded)に変換
//BASE64を利用したMIME変換
void PureMimeEncode(char *intext,
char *otext, int len)
{
unsigned char
*p;
unsigned long int x,x1;
unsigned char tmp[8]={0,0,0,0,0,0,0,0};
char
one[4]="A";
int add,len1,i,j;
add=0;
len1=len;
if (len%3!=0)
{
add=
3-(len%3);
len1=len/3*3;
}
p=(unsigned
char *)intext;
*otext=0;
for
(i=0; i<len1; i+=3) {
x=(p[0]<<16)+(p[1]<<8)+p[2];
x1=(x>>18)&0x3f; one[0]=MimeEncodeTable[x1];
strcat(otext,one);
x1=(x>>12)&0x3f; one[0]=MimeEncodeTable[x1];
strcat(otext,one);
x1=(x>>06)&0x3f; one[0]=MimeEncodeTable[x1];
strcat(otext,one);
x1=( x )&0x3f; one[0]=MimeEncodeTable[x1];
strcat(otext,one);
p+=3;
}
if (add)
{
for (j=0 ; i<len;
i++,j++) tmp[j]=*p++;
x=(tmp[0]<<16)+(tmp[1]<<8)+tmp[2];
x1=(x>>18)&0x3f; one[0]=MimeEncodeTable[x1];
strcat(otext,one);
x1=(x>>12)&0x3f; one[0]=MimeEncodeTable[x1];
strcat(otext,one);
x1=(x>>06)&0x3f; one[0]=MimeEncodeTable[x1];
strcat(otext,one);
x1=( x )&0x3f; one[0]=MimeEncodeTable[x1];
strcat(otext,one);
}
//add=0
-> del=0, add=1 -> del=1, add=2 -> del=2
p=otext+strlen(otext)-1;
for (i=0; i<add; i++)
*p--='=';
}
//ユーザIDuserとパスワードpassからauth文字列(mime(user\0user\0pass))を作る
void
makeAuthPlain(char *user, char *pass, char
*auth)
{
int num,i;
char
plain[256];
strcpy(plain,user);
strcat(plain,"\t");
strcat(plain,user);
strcat(plain,"\t");
strcat(plain,pass);
//puts(plain);
num=strlen(plain);
for (i=0;i<num;i++) if
(plain[i]=='\t') plain[i]=0;
PureMimeEncode(plain,auth,num);
}
typedef struct
{
char smtpserver[128];
int
port;
char userID[128];
char
passwd[128];
char authplainstr[128];
}
smtp_t;
void
setAuthPlainString(smtp_t *smtp)
{
makeAuthPlain(smtp->userID, smtp->passwd,
smtp->authplainstr);
}
/*SMTPサーバsmtpにメールmailを送る関数 失敗したら0以外を戻す*/
int
sendMail(smtp_t *smtp, const char *smtpclient, mail_t
*mail)
{
SOCKET sock;
static char sndBuf[sndBufSize],rcvBuf[rcvBufSize];
setAuthPlainString(smtp);
/*SMTPサーバへの接続とリプライ受信*/
sock=connectSocket(smtp->smtpserver,"secure_smtp",(short
int)smtp->port);
if (sock == INVALID_SOCKET)
return 1;
receiveData(sock,rcvBuf,rcvBufSize);
if
('3'<rcvBuf[0]) {
printf("** ERROR **
%s\n",rcvBuf);
closesocket(sock);
WSACleanup();
return
1;
}
#ifdef REQUEST_INFO
/*情報要求がある場合(学習のため)*/
printf("connecting
Socket\n");
printf("receiving : %s\n",rcvBuf);
#endif
/*"EHLO"コマンドの送信とリプライ受信*/
/*クライアントの認証に失敗する場合はここの部分にsmtpサーバ名を書く*/
sprintf(sndBuf,"EHLO %s \r\n",smtpclient);
sendData(sock, sndBuf);
receiveData(sock,rcvBuf,rcvBufSize);
if
('3'<rcvBuf[0]) {
printf("** ERROR **
%s\n",rcvBuf);
closesocket(sock);
WSACleanup();
return
1;
}
#ifdef REQUEST_INFO
/*情報要求がある場合(学習のため)*/
printf("sending :
%s",sndBuf);
printf("receiving : %s\n",rcvBuf);
#endif
/*"AUTH
PLAIN"コマンドの送信とリプライ受信*/
sprintf(sndBuf,"AUTH PLAIN
%s\r\n",smtp->authplainstr);
sendData(sock,
sndBuf);
receiveData(sock,rcvBuf,rcvBufSize);
if
('3'<rcvBuf[0]) {
printf("** ERROR **
%s\n",rcvBuf);
closesocket(sock);
WSACleanup();
return
1;
}
#ifdef REQUEST_INFO
/*情報要求がある場合(学習のため)*/
printf("sending :
%s",sndBuf);
printf("receiving : %s\n",rcvBuf);
#endif
/*"MAIL
FROM"コマンドの送信とリプライ受信*/
sprintf(sndBuf,"MAIL
FROM:<%s>\r\n",mail->sender);
sendData(sock, sndBuf);
receiveData(sock,rcvBuf,rcvBufSize);
if
('3'<rcvBuf[0]) {
printf("** ERROR **
%s\n",rcvBuf);
closesocket(sock);
WSACleanup();
return
1;
}
#ifdef REQUEST_INFO
/*情報要求がある場合(学習のため)*/
printf("sending :
%s",sndBuf);
printf("receiving : %s\n",rcvBuf);
#endif
/*"RCPT
TO"コマンドの送信とリプライ受信*/
/*複数のあて先に同報送信する場合は,RCPT
TO"コマンドの送信とリプライ受信をここに並べればよい*/
sprintf(sndBuf,"RCPT
TO:<%s>\r\n",mail->receiver);
sendData(sock, sndBuf);
receiveData(sock,rcvBuf,rcvBufSize);
if
('3'<rcvBuf[0]) {
printf("** ERROR **
%s\n",rcvBuf);
closesocket(sock);
WSACleanup();
return
1;
}
#ifdef REQUEST_INFO
/*情報要求がある場合(学習のため)*/
printf("sending :
%s",sndBuf);
printf("receiving : %s\n",rcvBuf);
#endif
/*"DATA"コマンドの送信とリプライ受信*/
sprintf(sndBuf,"DATA\r\n");
sendData(sock,
sndBuf);
receiveData(sock,rcvBuf,rcvBufSize);
if
('3'<rcvBuf[0]) {
printf("** ERROR **
%s\n",rcvBuf);
closesocket(sock);
WSACleanup();
return
1;
}
#ifdef REQUEST_INFO
/*情報要求がある場合(学習のため)*/
printf("sending :
%s",sndBuf);
printf("receiving : %s\n",rcvBuf);
#endif
/*本文ヘッダの送信(サブジェクト)*/
sprintf(sndBuf,"Subject:
%s\r\n",mail->subject);
sendData(sock,
sndBuf);
#ifdef REQUEST_INFO
/*情報要求がある場合(学習のため)*/
printf("sending : %s",sndBuf);
#endif
/*本文ヘッダの送信(「To」行)*/
sprintf(sndBuf,"To:
%s\r\n",mail->receiver);
sendData(sock,
sndBuf);
#ifdef REQUEST_INFO
/*情報要求がある場合(学習のため)*/
printf("sending : %s",sndBuf);
#endif
/*本文ヘッダの送信(「From」行)*/
sprintf(sndBuf,"From:
%s\r\n",mail->sender);
sendData(sock,
sndBuf);
#ifdef REQUEST_INFO
/*情報要求がある場合(学習のため)*/
printf("sending : %s",sndBuf);
#endif
/*本文ヘッダの送信(ヘッダ終了の意味の空行)*/
sprintf(sndBuf,"\r\n");
sendData(sock,
sndBuf);
#ifdef REQUEST_INFO
/*情報要求がある場合(学習のため)*/
printf("sending : %s",sndBuf);
#endif
/*そのほかの本文ヘッダがある場合は本文本体送信前に記述すればよい*/
/*本文本体の送信*/
sprintf(sndBuf,"%s\r\n",mail->body);
sendData(sock, sndBuf);
#ifdef REQUEST_INFO
/*情報要求がある場合(学習のため)*/
printf("sending : %s",sndBuf);
#endif
/*本文終了マークの送信*/
sprintf(sndBuf,".\r\n");
sendData(sock,
sndBuf);
receiveData(sock,rcvBuf,rcvBufSize);
if
('3'<rcvBuf[0]) {
printf("** ERROR **
%s\n",rcvBuf);
closesocket(sock);
WSACleanup();
return
1;
}
#ifdef REQUEST_INFO
/*情報要求がある場合(学習のため)*/
printf("sending :
%s",sndBuf);
printf("receiving : %s\n",rcvBuf);
#endif
/*"QUIT"コマンドの送信とリプライ受信*/
sprintf(sndBuf,"QUIT\r\n");
sendData(sock,
sndBuf);
receiveData(sock,rcvBuf,rcvBufSize);
if
('3'<rcvBuf[0]) {
printf("** ERROR **
%s\n",rcvBuf);
closesocket(sock);
WSACleanup();
return
1;
}
#ifdef REQUEST_INFO
/*情報要求がある場合(学習のため)*/
printf("sending :
%s",sndBuf);
printf("receiving : %s\n",rcvBuf);
#endif
closesocket(sock);
WSACleanup();
return 0;
}
int
main()
{
mail_t mymail;
smtp_t smtp;
strcpy(mymail.subject,"test mail");
/*メールのサブジェクトの設定*/
strcpy(mymail.body,"test mail
body Hello from Tokyo."); /*メールの本文の設定*/
strcpy(mymail.sender,mymailaddress); /*送信者アドレスの設定*/
strcpy(mymail.receiver,mymailaddress);
/*受信者アドレスの設定*/
strcpy(smtp.smtpserver,smtpservername);
/*smtpサーバ名の設定*/
smtp.port=port;
/*ポート番号のセット*/
strcpy(smtp.userID,userID);
/*認証用ユーザIDの設定*/
strcpy(smtp.passwd,passwd);
/*パスワードの設定*/
sendMail(&smtp, smtpclientname,
&mymail);
return 0;
}