/**********************************************************************
Winsock2を用いたSMTPサンプルプログラム
このサンプルプログラムはSMTPサーバを介してテストメールを自分のメールア
ドレスに送付します。
(1)smtpサーバ名,自分のパソコン名,自分のメールアドレスは正しいもの
を指定してください。
(2)インターネット上のSMTPサーバでは,
POPサーバに一度ログインして認
証を受けないとメール受付を拒否するようになっています。通常のメーラで送
受信すると認証が有効になり,一定時間メールを受け付けるようになるので,
このソフトを試すことができるようになります。
(3)コンパイル時に「ws2_32.lib」をリンクしてください。
(4)本文で2バイトコード(漢字コードなど)を送信することは出来ません。
送信する場合はJISコードを使用し,本文ヘッダにそのことを記述してください。
(5)サブジェクトに2バイトコード(漢字コードなど)を送信することは出来
ません。送信する場合はmime変換をしてください。
**********************************************************************/
#define REQUEST_INFO
const
char *smtpservername="aaaa.tokyo-ct.ac.jp";
const char
*smtpclientname="happyday.tokyo-ct.ac.jp";
const char
*mymailaddress="taro@tokyo_ct.ac.jp";
/* 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
4096
#define rcvBufSize 1024
typedef struct
{
char sender[128];
/*送信者すなわち自分のメールアドレス*/
char
receiver[128]; /*送信先のメールアドレス*/
char subject[1024]; /*サブジェクト(件名)*/
char body[sndBufSize]; /*メール本体*/
} mail_t;
/*SMTPサーバsmtpserverにメールmailを送る関数 失敗したら0以外を戻す*/
int
sendMail(const char *smtpserver, const char *smtpclient, mail_t
*mail)
{
SOCKET sock;
static char sndBuf[sndBufSize],rcvBuf[rcvBufSize];
/*SMTPサーバへの接続とリプライ受信*/
sock=connectSocket(smtpserver,"mail",IPPORT_SMTP);
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
/*"HELO"コマンドの送信とリプライ受信*/
/*クライアントの認証に失敗する場合はここの部分にsmtpサーバ名を書く*/
sprintf(sndBuf,"HELO %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
/*"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;
strcpy(mymail.subject,"test mail");
/*メールのサブジェクトの設定*/
strcpy(mymail.body,"test mail
body Hello from Tokyo."); /*メールの本文の設定*/
strcpy(mymail.sender,mymailaddress); /*送信者アドレスの設定*/
strcpy(mymail.receiver,mymailaddress);
/*受信者アドレスの設定*/
sendMail(smtpservername,
smtpclientname, &mymail);
return
0;
}