gmailのsmtpを使うには?

解決


null  2009-07-24 08:56:45  No: 70654

最近ネットワークプログラミングについて勉強し始めた者なのですが、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;
}


subaru  2009-07-24 09:40:21  No: 70655

プログラムを書く前にtelnetなどで直接コマンド叩いて
通信できるか確認してみては?


aetos  2009-07-24 18:57:13  No: 70656

502エラーが出るのは何をした時(コード中のどこ)なのですか?


null  2009-07-24 21:57:04  No: 70657

------------------------------------------------------------------
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のときと同じ文字列])
------------------------------------------------------------------


YuO  2009-07-24 22:24:13  No: 70658

HELLOコマンドではなくExtended HELLOコマンド (EHLO) を使ってみてはどうですか。
502は実装されていないという意味なのですから。

一応,RFC 2821のF.3にはサーバーは引き続きサポートしろ (MUST) とは書いてありますが,所詮はAppendix部分ですから。

あと,RFC 2821は読みましょう。
http://www.ietf.org/rfc/rfc2821.txt
Appendix.Dに,典型的なシナリオが書いてあります。


subaru  2009-07-24 22:32:26  No: 70659

>------------------------------------------------------------------
>telnetコマンド(telnet smtp.gmail.com 587):失敗
>------------------------------------------------------------------
>220 mx.google.com ESMTP k35sm5167934waf.53
>[処理が終わらない]

これは接続できたので次のコマンド待ちの状態。
プログラムどおりならこのあとHELOを打ち込みます。

ちょっと試してみると、HELOでもEHLOでも
250が返されたので原因は別にあるかもしれません。


オショウ  2009-07-24 23:12:12  No: 70660

回答ではありません。

http://mail.google.com/support/bin/answer.py?hl=jp&answer=13287
gmailは、SSL認証なので、コードを見る限りプレーンテキストで
ID/PWDを送信しようとされてますが、当然そのようなエラーにな
るのでは?

SSL認証のコードを書く必要があるかと。

※  クライアントで SMTP 認証がサポートされていない場合は、
    Gmail メールへのアクセスはできません。と書かれてます!

以上。


オショウ  2009-07-24 23:14:11  No: 70661

追伸・・・

C#なら
http://prog.re-d.net/2009/05/02/gmail%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E3%83%A1%E3%83%BC%E3%83%AB%E9%80%81%E4%BF%A1-c.php

こんなに簡単にできます。

C++/CLI で、.NETのクラス使ったら?

以上。


null  2009-08-02 04:06:06  No: 70662

>SSL認証のコードを書く必要があるかと。

いろいろ調べてみたのですが、コーディングの仕方がまったく分かりません…
どなたか教えていただけないでしょうか…


オショウ  2009-08-02 04:43:50  No: 70663

検索してみた?

http://www.example-code.com/mfc/ssl_client.asp

中身、未確認ですが・・・

参考まで。


null  2009-08-02 07:43:15  No: 70664

素早いご回答ありがとうございます。
もうすこし頑張ってみます。

…英語はできないと駄目ですか…


null  2009-08-02 08:16:17  No: 70665

>http://www.example-code.com/mfc/ssl_client.asp

ここを参考に一応解決いたしました。
ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加