最近ネットワークプログラミングについて勉強し始めた者なのですが、SMTPプログラミングをしていて、「SMTPサーバとしてsmtp.gmail.comが使える」ようなことを聞いたので、実際にやってみようと思ったのですが、いざ通信するとなると、サーバからはいつも502エラーが返されて、うまくいきません。ググってみても、(自分の理解力が足りないせいかもしれませんが)恥ずかしながらなにがいけないのかよくわかりませんでした。どなたかわかり易く原因と対処法などを教えていただけませんでしょうか?
ソースコードは下のとおりです(まずはお手本通りということで某参考書の付録ソースコードにちょっと手を加えただけです。)
#include <stdio.h>
#include <winsock2.h>
#include <mbstring.h>
int MySend(SOCKET, char *);
int MyRecvAndPrint(SOCKET);
void MySJisToJis(unsigned char *, unsigned char *);
int main()
{
WSADATA wsaData;
LPHOSTENT lpHost;
SOCKET s;
SOCKADDR_IN sockadd;
char szServer[256], szStr[1024], jisStr[1024];
char szFrom[64], szTo[64], szPort[8];
u_short port;
unsigned int addr;
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
printf("WSAStartupエラーです\n");
return -1;
}
strcpy(szServer, "smtp.gmail.com");
strcpy(szPort, "587");
port = (u_short)atoi(szPort);
strcpy(szFrom, "[送信元]@gmail.com");
strcpy(szTo, "[送信先]@gmail.com");
lpHost = gethostbyname(szServer);
if (lpHost == NULL) {
addr = inet_addr(szServer);
lpHost = gethostbyaddr((char *)&addr, 4, AF_INET);
wsprintf(szStr, "%sが見つかりません\n", szServer);
printf(szStr);
return -2;
}
s = socket(PF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET) {
printf("ソケットをオープンできません\n");
return -3;
}
sockadd.sin_family = AF_INET;
sockadd.sin_port = htons(port);
sockadd.sin_addr = *((LPIN_ADDR)*lpHost->h_addr_list);
if (connect(s, (PSOCKADDR)&sockadd, sizeof(sockadd)) != 0) {
printf("サーバーソケットに接続失敗\n");
closesocket(s);
WSACleanup();
return -4;
}
if (MyRecvAndPrint(s)) {
closesocket(s);
WSACleanup();
return -5;
}
wsprintf(szStr, "HELO %s", szServer);
if (MySend(s, szStr)) {
perror("HELO失敗\n");
closesocket(s);
WSACleanup();
return -6;
}
if (MyRecvAndPrint(s)) {
closesocket(s);
WSACleanup();
return -7;
}
wsprintf(szStr, "MAIL FROM:<%s>", szFrom);
if (MySend(s, szStr)) {
perror("FROM失敗\n");
closesocket(s);
WSACleanup();
return -8;
}
if (MyRecvAndPrint(s)) {
closesocket(s);
WSACleanup();
return -9;
}
wsprintf(szStr, "RCPT TO:<%s>", szTo);
if (MySend(s, szStr)) {
closesocket(s);
WSACleanup();
return -10;
}
if (MyRecvAndPrint(s)) {
closesocket(s);
WSACleanup();
return -11;
}
wsprintf(szStr, "DATA");
if (MySend(s, szStr)) {
closesocket(s);
WSACleanup();
return -12;
}
if (MyRecvAndPrint(s)) {
closesocket(s);
WSACleanup();
return -13;
}
if (MySend(s, "X-Mailer:Nekodemo-Wakaru Mailer Ver.0.5")) {
closesocket(s);
WSACleanup();
return -14;
}
if (MySend(s, "Subject:Test Mail")) {
closesocket(s);
WSACleanup();
return -15;
}
send(s, "\r\n", 2, 0);
while (1) {
printf("メール本文を1行ずつ入力します。終了時はピリオドのみ入力\n");
gets(szStr);
MySJisToJis((unsigned char *)szStr, (unsigned char *)jisStr);
if (MySend(s, jisStr)) {
closesocket(s);
WSACleanup();
return -17;
}
if (strcmp(szStr, ".") == 0)
break;
}
if (MyRecvAndPrint(s)) {
closesocket(s);
WSACleanup();
return -18;
}
MySend(s, "QUIT");
if (MyRecvAndPrint(s)) {
closesocket(s);
WSACleanup();
return -19;
}
closesocket(s);
WSACleanup();
printf("通信を終了しました\n");
return 0;
}
int MySend(SOCKET s, char *lpszBuf)
{
int nRtn;
char szBuf[1024];
wsprintf(szBuf, "%s\r\n", lpszBuf);
nRtn = send(s, szBuf, (int)strlen(szBuf), 0);
if (nRtn == SOCKET_ERROR) {
perror("sendエラーです\n");
return -1;
}
return 0;
}
int MyRecvAndPrint(SOCKET s)
{
int nRtn;
char szBuf[1024];
memset(szBuf, '\0', sizeof(szBuf));
nRtn = recv(s, szBuf, (int)sizeof(szBuf) - 1, 0);
if (nRtn == SOCKET_ERROR) {
perror("recv失敗です\n");
return -1;
}
printf("%s", szBuf);
return 0;
}
void MySJisToJis(unsigned char *lpszOrg, unsigned char *lpszDest)
{
int i = 0, iR = 0, c;
BOOL bSTART = FALSE;
while (1) {
if (_ismbblead(lpszOrg[i]) && bSTART == FALSE) {
lpszDest[iR] = 0x1b;
lpszDest[iR + 1] = 0x24;
lpszDest[iR + 2] = 0x42;
c = MAKEWORD(lpszOrg[i + 1], lpszOrg[i]);
lpszDest[iR + 3] = (unsigned char)HIBYTE(_mbcjmstojis(c));
lpszDest[iR + 4] = (unsigned char)LOBYTE(_mbcjmstojis(c));
bSTART = TRUE;
i += 2;
iR += 5;
if (!_ismbblead(lpszOrg[i])) {
lpszDest[iR] = 0x1b;
lpszDest[iR + 1] = 0x28;
lpszDest[iR + 2] = 0x42;
bSTART = FALSE;
iR += 3;
}
continue;
}
if (_ismbblead(lpszOrg[i]) && bSTART) {
c = MAKEWORD(lpszOrg[i + 1], lpszOrg[i]);
lpszDest[iR] = (unsigned char)HIBYTE(_mbcjmstojis(c));
lpszDest[iR + 1] = (unsigned char)LOBYTE(_mbcjmstojis(c));
i += 2;
iR += 2;
if (!_ismbblead(lpszOrg[i])) {
lpszDest[iR] = 0x1b;
lpszDest[iR + 1] = 0x28;
lpszDest[iR + 2] = 0x42;
bSTART = FALSE;
iR += 3;
}
continue;
}
if (lpszOrg[i] == '\r') {
lpszDest[iR] = '\n';
i += 2;
iR++;
continue;
}
if (lpszOrg[i] == '\0') {
lpszDest[iR] = lpszOrg[i];
break;
}
lpszDest[iR] = lpszOrg[i];
iR++;
i++;
}
return;
}
プログラムを書く前にtelnetなどで直接コマンド叩いて
通信できるか確認してみては?
502エラーが出るのは何をした時(コード中のどこ)なのですか?
------------------------------------------------------------------
pingコマンド(smtp.gmail.com):成功
------------------------------------------------------------------
Pinging gmail-smtp-msa.l.google.com [209.85.147.109] with 32 bytes of data:
Reply from 209.85.147.109: bytes=32 time=98ms TTL=240
Reply from 209.85.147.109: bytes=32 time=97ms TTL=240
Reply from 209.85.147.109: bytes=32 time=98ms TTL=240
Reply from 209.85.147.109: bytes=32 time=98ms TTL=240
Ping statistics for 209.85.147.109:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 97ms, Maximum = 98ms, Average = 97ms
------------------------------------------------------------------
------------------------------------------------------------------
telnetコマンド(telnet smtp.gmail.com 587):失敗
------------------------------------------------------------------
220 mx.google.com ESMTP k35sm5167934waf.53
[処理が終わらない]
------------------------------------------------------------------
------------------------------------------------------------------
telnetコマンド(telnet 209.85.147.109 587):失敗
------------------------------------------------------------------
220 mx.google.com ESMTP n9sm5237592wag.58
[処理が終わらない]
------------------------------------------------------------------
------------------------------------------------------------------
(自プログラム)
------------------------------------------------------------------
ソケット接続時の返事のみ220
(220 mx.google.com ESMTP [ランダムな半角英数字の羅列])
HELOコマンドから以下ずっと502
(502 5.5.1 Unrecognized command. [220のときと同じ文字列])
------------------------------------------------------------------
HELLOコマンドではなくExtended HELLOコマンド (EHLO) を使ってみてはどうですか。
502は実装されていないという意味なのですから。
一応,RFC 2821のF.3にはサーバーは引き続きサポートしろ (MUST) とは書いてありますが,所詮はAppendix部分ですから。
あと,RFC 2821は読みましょう。
http://www.ietf.org/rfc/rfc2821.txt
Appendix.Dに,典型的なシナリオが書いてあります。
>------------------------------------------------------------------
>telnetコマンド(telnet smtp.gmail.com 587):失敗
>------------------------------------------------------------------
>220 mx.google.com ESMTP k35sm5167934waf.53
>[処理が終わらない]
これは接続できたので次のコマンド待ちの状態。
プログラムどおりならこのあとHELOを打ち込みます。
ちょっと試してみると、HELOでもEHLOでも
250が返されたので原因は別にあるかもしれません。
回答ではありません。
http://mail.google.com/support/bin/answer.py?hl=jp&answer=13287
gmailは、SSL認証なので、コードを見る限りプレーンテキストで
ID/PWDを送信しようとされてますが、当然そのようなエラーにな
るのでは?
SSL認証のコードを書く必要があるかと。
※ クライアントで SMTP 認証がサポートされていない場合は、
Gmail メールへのアクセスはできません。と書かれてます!
以上。
追伸・・・
こんなに簡単にできます。
C++/CLI で、.NETのクラス使ったら?
以上。
>SSL認証のコードを書く必要があるかと。
いろいろ調べてみたのですが、コーディングの仕方がまったく分かりません…
どなたか教えていただけないでしょうか…
検索してみた?
http://www.example-code.com/mfc/ssl_client.asp
中身、未確認ですが・・・
参考まで。
素早いご回答ありがとうございます。
もうすこし頑張ってみます。
…英語はできないと駄目ですか…
>http://www.example-code.com/mfc/ssl_client.asp
ここを参考に一応解決いたしました。
ありがとうございました。
ツイート | ![]() |