C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 Q&A
C++Builder Programming Q&A
[37540] Re:Re:Re:Re:[SMTP] SMTP 서버 없이 전송되게 하는 코드나 컴포넌트가 있을까요?
초보자 [] 1316 읽음    2004-10-08 16:13
멀더님, 임문환님... 두분모두 진심으로 감사드립니다.
telnet을 사용해서, 메일보내는부분과 mx host query하는부분 모두 공부하고는 있지만,,,
아직 코딩실력이 많이 모자라서 헤매고 있었는데...
두분의 도움으로 이해가 막 될려고(?) 하고 있습니다.

좋은 하루 되세요.

멀더 님이 쓰신 글 :
: 멀더입니다. 수정했습니다.
:
: 필요하신건 수신자메일도메인의 MX 호스트 값을 구하시면 됩니다.
: MX 호스트를 구한다음 그호스트를 SMTP OutBound서버로 이용해
:  임문환님의 방법과 같이 SMTP 발송하시면 OK.
: 그러면 Relay용 SMTP outbound 서버가 필요없어 지지요...;)
:
: 참고 : http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tutorial&no=58
:
:
: 초보자 님이 쓰신 글 :
: : 임문환.실업자 님이 쓰신 글 :
: : : 초보자 님이 쓰신 글 :
: : : : SMTP 서버 없이 이메일 전송할수 있는 예제코드나, 컴포넌트 없을까요?
: : : : 델마당이나 여기저기 기웃거리고, 나름대로 SMTP 쪽 공부한다고 하는데....
: : : : 머리가 나쁜지 영 이해를 하지 못하겠네요.
: : : :
: : : : 없다면, 구현을 하기위한 대략적인 OUTLINE이라도 그려주실분 없나요?
: : : : 그럼 즐거운 하루 되시길 바랍니다.
: : :
: : : 이 것을 어디에 사용하려 하시는지 궁금해지네요.
: : : 컴포넌트로 되어 있는 것은 모르겠구요 간단히 흐름만을 말씀드리겠습니다.
: : :
: : : SMTP(Simple Mail Transfer Protocol) Sender 구현에 관해
: : :
: : : 관련 RFC: rfc821(http://www.ietf.org/rfc/rfc0821.txt?number=821)
: : :
: : : 0. 아래 작업은 보통 별도의 스레드 내에서 하는 것이 좋음
: : :   애플리케이션 내의 공용 자원들에 대해서는 동기화 메커니즘을 사용하는 게 안전함.
: : :
: : : 1. SMTP Receiver에 접속
: : :  - SMTP 기본 포트는 25이지만 이를 무시하는 경우도 있으므로 각 서버마다 실제 포트를 알아야 함
: : :  - 호스트와 포트를 알았다고 해도 등록된 IP들에만 개방하는 경우가 있어 접속 불가능할 수도 있음
: : :  - TCP blocking 모드를 사용
: : : 
: : : 2. 일단 접속에 성공하면 Receiver 쪽에서 응답코드를 반환하게 됨.
: : :  즉, 아래와 같은 형식의 문자열을 반환함.
: : :  220 USC-ISIF.ARPA Simple Mail Transfer Service Ready\r\n
: : :  Sender는 이를 받아서 코드가 220인지 확인해야 하고 220이 아니면 메일을 보낼 수 없음.
: : : 
: : : 3. Sender는 "HELO"를 아래와 같은 형식으로 Receiver에게 보내야 함.
: : :    HELO HostNameOfSender\r\n
: : :    예: HELO LBL-UNIX.ARPA\r\n
: : :    Receiver는 이를 받고 확인차원에서 아래 메시지를 보냄
: : :    250 HostNameOfReceiver\r\n
: : :    예: 250 USC-ISIF.ARPA\r\n
: : :    응답코드가 250이 아니면 메일을 보낼 수 없음.
: : :   
: : : 4. 아래 메시지를 Receiver에 보냄
: : :    MAIL FROM:<mo@LBL-UNIX.ARPA>\r\n
: : :    위에서 <> 안에 보내는이의 메일주소를 넣으면 됨.
: : :    Receiver가 메일을 처리할 의사가 있으면 아래와 같은 형식으로 250 응답코드를 보내게 됨.
: : :    250 OK\r\n
: : :    응답코드가 250이 아니면 메일을 처리할 의사가 없는 것임.
: : :    응답코드는 여러가지 중 하나인데 각 응답코드에 대해서는 rfc821 문서를 참고.
: : :
: : : 5. 아래와 같은 형식으로 받는이의 메일주소를 Receiver에게 보냄
: : :   RCPT TO:<fred@USC-ISIF.ARPA>\r\n
: : :   Receiver가 250 또는 251이 아닌 응답코드를 보내면 메일을 보낼 수 없음.
: : :   251인 경우 포워드를 뜻하고 아래와 같은 형식으로 포워드 메일주소를 Receiver가 보내줌
: : :   251 User not local; will forward to <Jones@USC-ISI.ARPA>\r\n
: : :   각 응답코드에 대해서는 rfc821 문서를 참고.
: : :
: : : 6. 아래 메시지를 Receiver에게 보냅니다.
: : :    DATA\r\n
: : :    이에 대해 Receiver가 354가 아닌 응답코드를 보내면 메일을 보낼 수 없음.
: : :    Receiver가 354 응답코드를 보낼 때는 아래와 같이 메일의 끝을 지정하는 방법을 같이 보냅니다.
: : :    아래의 경우 메일 내용을 Receiver가 수신받는 중에 C언어 문자열로 말하자면 "\r\n.\r\n"을 만나면 그게 메일의 끝표시로 간주하겠다는 뜻입니다.
: : :    따라서 보내는 쪽에서는 메일끝에 "\r\n.\r\n"를 추가로 보내면 되는 것이지요. 보통 이것을 사용합니다.
: : :    354 Start mail input; end with <CRLF>.<CRLF>\r\n
: : :   
: : : 7. 메일 내용(메일헤더 등 메일의 모든 내용)을 보냅니다.
: : :
: : : 8. 메일의 내용을 다 보냈으면 끝표시를 보냅니다.
: : :   위 예의 경우 "\r\n.\r\n"를 보냅니다.
: : :   Receiver는 아래 응답을 보낼 것입니다.
: : :   250 OK\r\n
: : :  
: : : 9. 마지막으로 종료 메시지를 보냅니다.
: : :   QUIT\r\n
: : :   Receiver는 이에 대해 아래와 같은 형식의 응답 메시지를 보냅니다.
: : :   221 USC-ISIF.ARPA Service closing transmission channel\r\n
: : :  
: : : 10. TCP 커넥션을 끊습니다.
: : :
: : :
: : : 참고로, 메일 내용을 어떻게 구성해야 하는지는,
: : : 어떤 메일이든 하나 골라서 파일로 저장한 다음
: : : 텍스트 편집기로 열어보면 그 구조가 모두 나와 있으므로 이를 참고하면 됩니다.
: : : 한편, 첨부 파일 등 ASCII 코드 범위를 벗어난 Byte가 있는 경우는 인코딩을 해야하는데 보통 Base64 인코딩을 사용합니다. 제목에 한글이 있는 경우와 첨부파일은 인코딩해야 한다고 보면 됩니다.
: : :
: : :
: : : /////////////////////////////////////////////////////////////////////////
: : : void __fastcall TSendMailThread::Execute()
: : : {
: : :   CSock1 = new TClientSocket(NULL);
: : :   CSock1->Active=false;
: : :   CSock1->ClientType=ctBlocking;
: : :   CSock1->Port=25;
: : :   CSock1->OnConnect = ClientSocket1Connect;
: : :    CSock1->Host=Mail->ReceiverSMTP;
: : :    CSock1->Open();
: : : .
: : : .
: : : .
: : :
: : : }
: : :
: : : /////////////////////////////////////////////////////////////////////////
: : : void __fastcall TSendMailThread::ClientSocket1Connect(TObject *Sender,
: : :       TCustomWinSocket *Socket)
: : : {
: : :   SendMail();
: : : }
: : :
: : : /////////////////////////////////////////////////////////////////////////
: : : int __fastcall TSendMailThread::SendMail()
: : : {
: : :  String toAddress;
: : :  String rep="";
: : :  int repCode;
: : :  String body;
: : :  TReceiver *receiver;
: : :
: : :   if(!CSock1) return -1;
: : :
: : :   toAddress = receiver->Id + "@" + Mail->ReceiverDomain;
: : :
: : :   Completed=false;
: : :
: : :   pStream = new TWinSocketStream(CSock1->Socket, 30000);
: : :   try
: : :   {
: : :     while (!Terminated && CSock1->Active)
: : :     {
: : :       try
: : :       {
: : :         rep = GetReply();
: : :         if(rep.IsEmpty()) ;
: : :         if(!extractReplyCode(rep,repCode)) ;
: : :
: : :         if(repCode!=220)
: : :         {
: : :          receiver->Success=false;
: : :          receiver->TryLater=true;
: : :          receiver->ResultCode=repCode;
: : :          return repCode;
: : :         }
: : :
: : :         SendMessage("HELO " + Mail->SenderSMTP + "\r\n");
: : :         rep = GetReply();
: : :         if(rep.IsEmpty()) ;
: : :         if(!extractReplyCode(rep,repCode)) ;
: : :
: : :         if(repCode!=250)
: : :         {
: : :          receiver->Success=false;
: : :          receiver->TryLater=true;
: : :          receiver->ResultCode=repCode;
: : :          return repCode;
: : :         }
: : :
: : :         SendMessage(String("MAIL FROM: ") + "<" + Mail->From + ">\r\n");
: : :         rep = GetReply();
: : :         if(rep.IsEmpty()) ;
: : :         if(!extractReplyCode(rep,repCode)) ;
: : :
: : :         if(repCode!=250)
: : :         {
: : :          receiver->Success=false;
: : :          receiver->ResultCode=repCode;
: : :
: : :          if(repCode==500 || repCode==501 || repCode==421)
: : :          {
: : :            receiver->TryLater=false;
: : :          }
: : :          else
: : :          {
: : :            receiver->TryLater=true;
: : :          }
: : :          return repCode;
: : :         }
: : :
: : :         SendMessage(String("RCPT TO: ") + "<" + toAddress + ">\r\n");
: : :         rep = GetReply();
: : :         if(rep.IsEmpty()) ;
: : :         if(!extractReplyCode(rep,repCode)) ;
: : :
: : :         if(repCode!=250 && repCode!=251)
: : :         {
: : :          receiver->Success=false;
: : :          receiver->TryLater=false;
: : :          receiver->ResultCode=repCode;
: : :          if(repCode==550)
: : :          {
: : :          }
: : :          else if(repCode==551)
: : :          {
: : :            Mail->NewReceiverAddress=GetAddress(rep);
: : :          }
: : :          else if((repCode>=500 && repCode<=504) || repCode==553)
: : :          {
: : :          }
: : :          else if(repCode==552 || repCode==450 ||repCode==451 ||repCode==452)
: : :          {
: : :            receiver->TryLater=true;
: : :          }
: : :          else
: : :          {
: : :            receiver->TryLater=true;
: : :          }
: : :          return repCode;
: : :         }
: : :
: : :         SendMessage(String("DATA\r\n"));
: : :         rep = GetReply();
: : :         if(rep.IsEmpty()) ;
: : :         if(!extractReplyCode(rep,repCode)) ;
: : :
: : :         if(repCode!=354)
: : :         {
: : :          receiver->Success=false;
: : :          receiver->TryLater=true;
: : :          receiver->ResultCode=repCode;
: : :          return repCode;
: : :         }
: : :
: : :         body= "To: " + toAddress + " <" + toAddress + ">\r\n";
: : :         body=body+Mail->Headers;
: : :         body = body + Mail->Body1;
: : :         body = body + Mail->Body3 + Mail->Attachment + "\r\n.\r\n";
: : :
: : :         SendMessageBody(body);
: : :
: : :         rep = GetReply();
: : :         if(rep.IsEmpty()) ;
: : :         if(!extractReplyCode(rep,repCode)) ;
: : :
: : :         if(repCode!=250)
: : :         {
: : :          receiver->Success=false;
: : :          receiver->TryLater=true;
: : :          receiver->ResultCode=repCode;
: : :          return repCode;
: : :         }
: : :
: : :         SendMessage("QUIT\r\n");
: : :         rep = GetReply();
: : :         if(rep.IsEmpty()) ;
: : :         if(!extractReplyCode(rep,repCode)) ;
: : :
: : :         CSock1->Close();
: : :
: : :         receiver->Success=true;
: : :         receiver->TryLater=false;
: : :         receiver->ResultCode=repCode;
: : :         return 0;
: : :       }
: : :       catch (Exception &e)
: : :       {
: : :        //ShowMessage(e.Message);
: : :        CSock1->Close();
: : :        return -1;
: : :       }
: : :     }
: : :   }
: : :   __finally
: : :   {
: : :     delete pStream;
: : :   }
: : :
: : :   return 0;
: : : }
: : :
: : :
: : : /////////////////////////////////////////////////////////////////////////
: : : void __fastcall TSendMailThread::SendMessage(const String& msg)
: : : {
: : :   pStream->Write(msg.c_str(), msg.Length());
: : : }
: : :
: : : /////////////////////////////////////////////////////////////////////////
: : : String __fastcall TSendMailThread::GetReply(void)
: : : {
: : :   char buffer[1024];
: : :   memset(buffer, 0, 1024);
: : :   if(pStream->WaitForData(10000))
: : :   {
: : :       if(pStream->Read(buffer, 1024) == 0)
: : :       {
: : :          CSock1->Close();
: : :       }
: : :       return String(buffer);
: : :   }
: : :   else
: : :   {
: : :      CSock1->Close();
: : :      return "";
: : :   }
: : :   return String(buffer);
: : : }
: :
: : 감사합니다.
: : 어디에 쓰려고 하는게 아니구요...
: : 그냥 순수히 학문적인 취지에서 질문한 겁니다.
: : 궁금해 하시는 것처럼... 어디(?)에 쓰지는 않을겁니다.
: : 빌더에 있는 smtp 컴퍼넌트를 사용해서는 성공을 했는데, smtp 서버없이는 어떻게 될까?하고 궁금해서 질문을 올린겁니다.
: : 답변 감사드리구요.. 좋은 하루되세요.

+ -

관련 글 리스트
37524 [SMTP] SMTP 서버 없이 전송되게 하는 코드나 컴포넌트가 있을까요? 초보자 850 2004/10/07
37529     Re:[SMTP] SMTP 서버 없이 전송되게 하는 코드나 컴포넌트가 있을까요? 임문환.실업자 1103 2004/10/07
37533         Re:Re:[SMTP] SMTP 서버 없이 전송되게 하는 코드나 컴포넌트가 있을까요? 초보자 1331 2004/10/07
37535             Re:Re:Re:[SMTP] SMTP 서버 없이 전송되게 하는 코드나 컴포넌트가 있을까요? 멀더 1063 2004/10/08
37540                 Re:Re:Re:Re:[SMTP] SMTP 서버 없이 전송되게 하는 코드나 컴포넌트가 있을까요? 초보자 1316 2004/10/08
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.