C3Lab研究室

Back to Title Page(OpenLab)タイトルページへ戻る

最終更新日: 1998年 11月 02日 月曜日

*Network Software構築シリーズ1 CSocketクラスをSMTPへカスタマイズ


 VisualStudio 6.0を使用するようになってMFCでより簡単に、 かつ複雑なプログラムが構築できるようになってきましたが、まだネットワーク関連は簡単 とはいかないようです。とくに、FTP・GOPHER・HTTPはそれぞれのクラスがサ ポートされ簡単にアクセスできるようになりましたが、SMTPなどのメールサーバーへのア クセスのためにはいまだにCSocketを通してWindockを使用することになり ます。
 今回、簡単に電子メールを送信するために関数を作成してみました。使用上の注意は、

MFCアプリケーションウィザードでWinsockを使用するオプション付で プロジェクトを作成する

 ことぐらいで、あとはこのリストをカット&ペーストすることで作成できます。本文 中は日本語が使用できるように、サーバーに対してはquoted-printableフォーマットで7ビッ トテキスト出力をしています。タイトルには日本語がしようできないサーバーもあります。
 こうしたサーバーの制限については電子メールサーバー次第ともいえますのでここのサーバー にあわせて組む必要が有るかもしれません。ここでは基本関数として、かつまたquoted-printable フォーマット文字列への変換方法についてのサンプルとして掲載しておきます。

 同様の方法で非同期Winsock関数を使用しながら同期型の様な形でソケットを 使用できるためPOP3への変更なども簡単に行えることでしょう。

CSock クラスを使用したサンプル関数 : SendMailMessage

BOOL SendMailMessage(CString szServer,
    CString szFrom, CString szTo, CString szSubject, CString szMessage,BOOL bSilent){
    CSock cSock;
    CString strResponse;

    if (!cSock.Create(szServer, 25))
    {
        if(bSilent==FALSE)     AfxMessageBox("Could not connect to server");
        return FALSE;
    }
    // Read response
    if (cSock.Receive(&strResponse) == SOCKET_ERROR)
    {
        if(bSilent==FALSE)     cSock.ReportError(cSock.GetLastError());
        return FALSE;
    }
    if (strResponse.Left(3) != _T("220"))
    {
        CString strError = "ERROR: SMTP サーバーから正常な応答が返ってきませんでした\r\n";
        strError += strResponse;
        if(bSilent==FALSE)     AfxMessageBox(strError);
        cSock.SendQuit();
        return FALSE;
    }
    cSock.SendHelo(szFrom);    // Send "HELO"
    if (cSock.Receive(&strResponse) == SOCKET_ERROR)
    {
        if(bSilent==FALSE)     cSock.ReportError(cSock.GetLastError());
        return FALSE;
    }
    if (strResponse.Left(3) != _T("250"))
    {
        CString strError = "ERROR: 送信に失敗しました(送信者エラー)\r\n";
        strError += strResponse;
        if(bSilent==FALSE)     AfxMessageBox(strError);
        cSock.SendQuit();
        return FALSE;
    }

    //
    cSock.SendFrom(szFrom);    // Send "FROM"
    if (cSock.Receive(&strResponse) == SOCKET_ERROR)
    {
        if(bSilent==FALSE)     cSock.ReportError(cSock.GetLastError());
        return FALSE;
    }
    if (strResponse.Left(3) != _T("250"))
    {
        CString strError = "ERROR: 送信に失敗しました(送信者エラー)\r\n";
        strError += strResponse;
        if(bSilent==FALSE)     AfxMessageBox(strError);
        cSock.SendQuit();
        return FALSE;
    }
    cSock.SendTo(szTo);    // Send "RCPT"
    if (cSock.Receive(&strResponse) == SOCKET_ERROR)
    {
        if(bSilent==FALSE)     (cSock.GetLastError());
        return FALSE;
    }
    if (strResponse.Left(3) != _T("250"))
    {
        CString strError = "ERROR: 送信エラーが発生しました\r\n";
        strError += strResponse;
        if(bSilent==FALSE)     AfxMessageBox(strError);
        cSock.SendQuit();
        return FALSE;
    }

    cSock.SendData();    // Send the "DATA" line
    if (cSock.Receive(&strResponse) == SOCKET_ERROR)
    {
        if(bSilent==FALSE)     cSock.ReportError(cSock.GetLastError());
        return FALSE;
    }
    if (strResponse.Left(3) != _T("354"))
    {
        CString strError = "ERROR: 送信エラーが発生しました(データ)\r\n";
        strError += strResponse;
        if(bSilent==FALSE)     AfxMessageBox(strError);
        cSock.SendQuit();
        return FALSE;
    }

    cSock.SendMIME             (1,0);     // Send MIME 1.0
    cSock.SendContentType    ();         // Send Content type
    cSock.SendEncodeType    ();         // Send Content Encode Type to Quoted-printable
    cSock.SendXMailer         ("Sample Mail Send Soft");     // Send Mail soft
    cSock.SendSubject         (cSock.ConvertQuoted(szSubject));         // Send the "Subject"

    // Message Body
    if (cSock.Send(cSock.ConvertQuoted(szMessage)) == SOCKET_ERROR)
    {
        if(bSilent==FALSE)cSock.ReportError(cSock.GetLastError());
        return FALSE;
    }
    cSock.SendTermination();    // Send the termination
    if (cSock.Receive(&strResponse) == SOCKET_ERROR)
    {
        if(bSilent==FALSE) cSock.ReportError(cSock.GetLastError());
        return FALSE;
    }
    if (strResponse.Left(3) != _T("250"))
    {
        CString strError = "ERROR: 送信エラーが発生しました(メッセージ)\r\n";
        strError += strResponse;
        if(bSilent==FALSE)     AfxMessageBox(strError);
        cSock.SendQuit();
        return FALSE;
    }
    cSock.SendQuit();
    return TRUE;
}

クラスの定義リスト : CSock


#ifndef __CLASS_CSOCK__
#define __CLASS_CSOCK__


class CSock : public CSocket {
    public:
        int Create(LPCTSTR szServer,int nPort,UINT nSocketPort = 0, int nSocketType = SOCK_STREAM, LPCTSTR lpszSocketAddress = NULL);
        int Create(CString sServer ,int nPort,UINT nSocketPort = 0, int nSocketType = SOCK_STREAM, LPCTSTR lpszSocketAddress = NULL);
    public:
        int Send(CString s,int nFlags=0);
        int Send(LPCTSTR s,int nFlags=0);
    public:    //
        int Receive(CString *s,int nFlags = 0);
        void ReportError(int nError);
    public: // 文字列変換
        CString ConvertQuoted(CString szMessage); // quoted-printable文字列に変換

    //----------------------------------------------------
    // Send SMTP Command Messages
    public:
        int SendHelo(LPCTSTR szHelo,int nFlags = 0);
        int SendHelo(CString szHelo,int nFlags = 0);
        int SendFrom(LPCTSTR szFrom,int nFlags = 0);
        int SendFrom(CString szFrom,int nFlags = 0);
        int SendTo    (LPCTSTR szTo,int nFlags = 0);
        int SendTo    (CString szTo,int nFlags = 0);
        int SendData(int nFlags = 0);
        int SendSubject(LPCTSTR szSubject,int nFlags=0);
        int SendSubject(CString szSubject,int nFlags=0);
        int SendMIME(int nMajor,int nMinor,int nFlags=0);
        int SendContentType(int nFlags=0);                     //      text/plain;
        int SendContentType(LPCTSTR szType,int nFlags=0);
        int SendContentType(CString szType,int nFlags=0);
        int SendXMailer(LPCTSTR szXMailer,int nFlags=0);
        int SendXMailer(CString szXMailer,int nFlags=0);
        int SendEncodeType(int nFlags=0);                     //      quoted-printable
        int SendEncodeType(LPCTSTR szType,int nFlags=0);
        int SendEncodeType(CString szType,int nFlags=0);
        int SendTermination(int nFlags = 0);
        int SendQuit(int nFlags = 0);
};
CString CSock::ConvertQuoted(CString szMessage){
    CString s;
    char *buf;
    char bf[8];
    int i,n;
    s = "";
    n = szMessage.GetLength();
    buf = (char*)malloc( n+20 );
    strcpy(buf,LPCTSTR(szMessage) );
    for(i=0;i<n;i++){
        int b;
        b = (int)(buf[i] & 0x00ff);
        if( (b<33)||(b>127)||(b==61) ){
            s += "=";
            wsprintf(bf,"%.2x",b);
            s += bf;
        }else{
            wsprintf(bf,"%c",b);
            s += bf;
        }
    }
    free(buf);
    return s;
}

int CSock::Create(CString sServer,int nPort,UINT nSocketPort, int nSocketType, LPCTSTR lpszSocketAddress){
    return( Create( LPCTSTR(sServer),nPort,nSocketPort,nSocketType,lpszSocketAddress) );
}

int CSock::Create(LPCTSTR szServer,int nPort,UINT nSocketPort, int nSocketType, LPCTSTR lpszSocketAddress){
    int n=CSocket::Create(nSocketPort,nSocketType,lpszSocketAddress);
    if(n==0)return n;
    return( CSocket::Connect(szServer,nPort) );
}

void CSock::ReportError(int nError){
    CString strError;
    strError.LoadString(nError);
    AfxMessageBox(strError);
}

int CSock::Receive(CString *s,int nFlags){
    static char buf[1024];
    ZeroMemory(buf,1024);
    int n = CSocket::Receive(buf,1024,nFlags);
    *s = buf;
    return n;
}

//------------------------------------------

int CSock::SendTermination(int nFlags){
    return ( Send("\r\n.\r\n") );
}
//------------------------------------------
int CSock::SendEncodeType(int nFlags){
    return(SendEncodeType("quoted-printable") );
}

int CSock::SendEncodeType(LPCTSTR szType,int nFlags)
{
    CString strCommand = "Content-Transfer-Encoding: ";
    strCommand += szType;
    strCommand += "\r\n";
    return( Send(strCommand,nFlags) );
}
int CSock::SendEncodeType(CString szType,int nFlags)
{
    CString strCommand = "Content-Transfer-Encoding: ";
    strCommand += szType;
    strCommand += "\r\n";
    return( Send(strCommand,nFlags) );
}
//------------------------------------------

int CSock::SendMIME(int nMajor,int nMinor,int nFlags){
    CString strCommand = "MIME-Version: ";
    char buf[80];
    wsprintf(buf,"%d.%d",nMajor,nMinor);
    strCommand += buf;
    strCommand += "\r\n";
    return( Send(strCommand,nFlags) );
}
//------------------------------------------
int CSock::SendContentType(int nFlags){
    return( SendContentType("text/plain;") );
}
int CSock::SendContentType(LPCTSTR szType,int nFlags)
{
    CString strCommand = "Content-Type: ";
    strCommand += szType;
    strCommand += "\r\n";
    return( Send(strCommand,nFlags) );
}
int CSock::SendContentType(CString szType,int nFlags)
{
    CString strCommand = "Content-Type: ";
    strCommand += szType;
    strCommand += "\r\n";
    return( Send(strCommand,nFlags) );
}
//------------------------------------------
int CSock::SendXMailer(LPCTSTR szXMailer,int nFlags)
{
    CString strCommand = "X-Mailer: <";
    strCommand += szXMailer;
    strCommand += ">\r\n";
    return( Send(strCommand,nFlags) );
}
int CSock::SendXMailer(CString szXMailer,int nFlags)
{
    CString strCommand = "X-Mailer: <";
    strCommand += szXMailer;
    strCommand += ">\r\n";
    return( Send(strCommand,nFlags) );
}

//------------------------------------------
int CSock::SendSubject(LPCTSTR szSubject,int nFlags)
{
    CString strCommand = "Subject: ";
    strCommand += szSubject;
    strCommand += "\r\n";
    return( Send(strCommand,nFlags) );
}
int CSock::SendSubject(CString szSubject,int nFlags)
{
    return( SendSubject(LPCTSTR(szSubject),nFlags) );
}
//------------------------------------------

int CSock::SendTo(LPCTSTR szTo,int nFlags)
{
    CString strCommand = "RCPT TO:<";
    strCommand += szTo;
    strCommand += ">\r\n";
    return( Send(strCommand,nFlags) );
}
int CSock::SendTo(CString szTo,int nFlags)
{
    return( SendTo(LPCTSTR(szTo),nFlags) );
}
//---------------------------------------------
int CSock::SendFrom(LPCTSTR szFrom,int nFlags)
{
    CString strCommand = "MAIL FROM:<";
    strCommand += szFrom;
    strCommand += ">\r\n";
    return( Send(strCommand,nFlags) );
}
int CSock::SendFrom(CString szFrom,int nFlags)
{
    return( SendFrom( LPCTSTR(szFrom),nFlags) );
}
//---------------------------------------------
int CSock::SendHelo(LPCTSTR szHelo,int nFlags)
{
    CString strCommand = "HELO ";

    if( strchr(szHelo,'@')==0)    strCommand += szHelo;
    else strCommand += (strchr(szHelo,'@')+1);
    strCommand += "\r\n";
    return( Send(strCommand,nFlags) );
}
int CSock::SendHelo(CString szHelo,int nFlags)
{
    return( SendHelo( LPCTSTR(szHelo),nFlags) );
}
//---------------------------------------------
int CSock::SendData(int nFlags){
    return( Send("DATA\r\n",nFlags) );
};

int CSock::SendQuit(int nFlags){
    return( Send("QUIT\r\n",nFlags) );
};
int CSock::Send(CString s,int nFlags){
    return( Send(LPCTSTR(s),nFlags) );
};
int CSock::Send(LPCTSTR s,int nFlags){
    return( CSocket::Send(s,strlen(s),nFlags) );
};

#endif // __CLASS_CSOCK__

Copyright (C) Kitaro 1998