웹마스터 팁
XE를 이용하여 SMTP 보내보기[개발자용]
2011.11.02 21:05
들어가기전에
오랜만에 팁을 올려봅니다. 해당 팁은 기존 XE Core에서 이용되는 mail()함수를 통한 이용방법이 아닌 별도의 SMTP 서버를 이용하여 전송할 수 있도록 해주는 팁 입니다.XE mail과 다른점
기존 방식에 문제점은 mail()를 이용하기 때문에 메일이 도착하지 못하는 경우가 발생하고 외부메일을 이용한 방식이 불가하다는 점 입니다. 이를 개선하여 어디든 도착가능 하도록하고 외부메일(gmail 등)의 SSL 인증 방식을 통해 서버내에 메일이 동작하지 않더라도 타 기관의 SMTP 서버를 통해 메일을 보낼 수 있습니다.주의점
- 앞으로 설명할 내용은 개발자용의 소스인지라 일반인들이 적용하기엔 무리가 따를 수 있습니다.- mail()가 아닌 fsockopen() 방식을 사용합니다. 본인의 호스팅이 각 기관(예 gmail) 경로로의 접근이 막혀있다면 외부경로로 하셔도 접근이 안되실 수 있습니다.
- 사설 ip의 경우 본인 컴에 sendmail 등을 올려도 메일발송이 안될 수가 있습니다.
소스
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | /** * @brief 메일 보내기 전 정보 초기화 **/ function sendMail( $args = false) { $oModuleModel = &getModel( 'module' ); $mail = new Mail; $mail ->smtp_secure = 'ssl' ; //일반 sendmail은 'tcp' $mail ->smtp_server = '+ 'smtp.gmail.com' ; $mail ->smtp_port = '465' ; $mail ->user = 'gmail메일주소' ; $mail ->pass = '패스워드' ; $mail ->setSender( $args ->sender->name, $args ->sender->email); $mail ->setTitle( $args ->title); $mail ->setContent( $args ->content); $mail ->setContentType( 'html' ); // 첨부파일 정리 if ( is_array ( $args ->attach)) { foreach ( $args ->attach as $key => $attach ) { $mail ->attach[] = $attach ; } } // 메일 보냄 foreach ( $args ->receiptor as $key => $receiptors ) { $mail ->setReceiptor( $receiptors ->name, $receiptors ->email); $this ->_sendMail( $mail ); } } /** * @brief 메일 보내기 **/ function _sendMail( $mail ) { // 영문이외의 문자 이름이 출력되도록 함 $sender_email = sprintf( "%s <%s>" , '=?utf-8?b?' . base64_encode ( $mail ->sender_name). '?= ' , $mail ->sender_email); $receiptor_email = sprintf( "%s <%s>" , '=?utf-8?b?' . base64_encode ( $mail ->receiptor_name). '?= ' + ', $mail ->receiptor_email); $boundary = "----==" .uniqid(rand(),true); // 바운드를 초기화한다 $eol = $GLOBALS [ '_qmail_compatibility' ] == 'Y' ? "\n" : "\r\n" ; $headers = sprintf( "MIME-Version: 1.0" . $eol . "Content-Type: Multipart/mixed;" . $eol . "\tboundary=\"%s\"" . $eol . "Subject: %s" . $eol . "From: %s" . $eol . "To: %s" . $eol . $eol , $boundary , $mail ->getTitle(), $sender_email , $receiptor_email ); $body = sprintf( "--%s" . $eol . "Content-Type: text/html; charset=utf-8" . $eol . "Content-Transfer-Encoding: base64" . $eol . $eol . "%s" . $eol . $eol , $boundary , $mail ->getHTMLContent() ); // 첨부파일 if ( is_array ( $mail ->attach)) { foreach ( $mail ->attach as $key => $path ) { $name = basename ( $path ->filename); $file = FileHandler::readFile( $path ->fileurl); $fileBody = sprintf( "--%s" . $eol . "Content-Type: application/octet-stream" . $eol . "Content-Transfer-Encoding: base64" . $eol . "Content-Disposition: attachment; filename=\"%s\"" . $eol . $eol . "%s" , $boundary , $name , chunk_split ( base64_encode ( $file )) ); $body .= $fileBody ; } } // 인증방식으로 메일을 보냄 if ( $smtp_socket = @ fsockopen ( $mail ->smtp_secure. "://" . $mail ->smtp_server, $mail ->smtp_port, $errno , $errstr , 5)) { $this ->_getMail( $smtp_socket ); @ fputs ( $smtp_socket , 'HELO ' . $mail ->smtp_secure. "://" . $mail ->smtp_server. $eol ); $this ->_getMail( $smtp_socket ); @ fputs ( $smtp_socket , 'AUTH LOGIN' . $eol ); $this ->_getMail( $smtp_socket ); @ fputs ( $smtp_socket , base64_encode ( $mail ->user). $eol ); $this ->_getMail( $smtp_socket ); @ fputs ( $smtp_socket , base64_encode ( $mail ->pass). $eol ); $this ->_getMail( $smtp_socket ); @ fputs ( $smtp_socket , 'MAIL From: <' . $mail ->sender_email. '>' . $eol ); $this ->_getMail( $smtp_socket ); @ fputs ( $smtp_socket , 'RCPT To: <' . $mail ->receiptor_email. '>' . $eol ); $this ->_getMail( $smtp_socket ); @ fputs ( $smtp_socket , 'DATA' . $eol ); $this ->_getMail( $smtp_socket ); $content = sprintf( "%s" . $eol . "%s" . $eol . "." . $eol , $headers , $body ); @ fputs ( $smtp_socket , $content ); $this ->_getMail( $smtp_socket ); @ fputs ( $smtp_socket , 'QUIT' . $eol ); @fclose( $smtp_socket ); } } /** * @brief 상대방의 응답을 기다립니다.(gmail등 인증 방식 사용시) **/ function _getMail( $socket = null) { if (! $socket ) return ; $i = 0; $response = '-' ; while ( $response == '-' && $i <10) { $response = @ fgets ( $socket , 256); if ( $response ) $response = substr ( $response ,3,1); else return ; $i ++; } } /** * @brief SMTP 서버가 동작하는지 체크 **/ function procNmsCheckSmtp() { // 일반 sendmail은 ssl이 아니라 tcp if ( $smtp_socket = @ fsockopen ( 'ssl' . "://" . 'smtp.gmail.com' , '465' , $errno , $errstr , 5)) { $message = @ fgets ( $smtp_socket , 512); @fclose( $smtp_socket ); } if (!preg_match( "/SMTP/" , $message )) return 'error' ; return '+ 'complete' ; } |
수행
1 2 3 4 5 6 7 8 9 10 11 12 | echo procNmsCheckSmtp(); $mail ->sender->name = '보내는이름' ; $mail ->sender->email = '보내는메일주소' ; $mail ->title = '제목' ; $mail ->content = '내용' ; $mail ->receiptor[0]->name = '받는사람이름' + '; $mail ->receiptor[0]->email = '받는사람메일주소' ; $mail ->attach[0]->fileurl = '경로/파일명' ; $mail ->attach[0]->filename = '파일이름' ; sendMail( $mail ); |
마무리
소스가 뭔가 이상하고 봐도 어렵죠? 실은 nmsXE에 적용했던 소스입니다. 제가 gmail을 통해 네이버, 다음 등 주요 포탈과 호스팅 계정 등으로 첨부파일 포함하여 전송확인은 했는데 예전 집이 사설ip여서 sendmail을 올려도 되질 못하여 내놓을 수 없다가 이번에 되는걸 확인하고 팁으로 적어보았습니다. 설명도 부족하고 개발자들이 보셔도 잘 사용할지 못할지 모르겠지만 위와 같은 형식으로 사용하시면 기존에 메일을 발송해도 못받으시거나 하던 문제는 해결 됩니다.
나중에 따로 배포본으로 만들어서 자료실에 올리던가 해야겠습니다. 하지만 위 기능하나만 가지고 내는건 뭐해서 제가 제작하는 모듈에 알림이 기능으로써 각각 집어넣을지 단체메일링 같은 좀 살을 붙여서 모듈로 배포할지는 고민중입니다.
- [2016/10/17] 묻고답하기 https 관련 질문입니다 ㅠㅠ *1
- [2016/04/26] 묻고답하기 회원가입(휴대폰인증모듈)페이지 속도 문제.. *3
- [2016/04/13] 웹마스터 팁 IIS에서 HTTPS를 사용하기 위한 SSL설정 (letsencrypt 인증서 설치, 갱신)
- [2016/03/18] 묻고답하기 SSL 테스트, B등급에서 더 올릴 수 있나요? *2
- [2016/01/07] 묻고답하기 ssl 항상사용 후 접근이 안되고 있습니다.. *5
댓글 10
-
tobor
2011.11.02 22:20
-
tobor
2011.11.03 01:01
gmail등 ssl이용한 smtp사용시 extension 모듈인 php_openssl 로드 되어 있어야하는데 대부분의 호스팅 회사들은 php_openssl 로드하지 않고있습니다.^^;
-
제 호스팅은 올라가있네요. ^^ 만약 그런 이유로 ssl이 안된다하시면 tcp로 접근되는 SMTP로 사용하시면 되겠네요.
-
똑디
2011.11.02 22:37
언젠가는 단체메일링 기능이 나오겠네요. 기대해 봅니다.
-
snows96
2011.11.03 21:26
그런데 사설IP라 함은 광랜 등등 가정에서 사용하는 인터넷 아닌가요???
희안하게 전 저런외부 SMTP사용하지 않고서도 그냥 sendmail같은 서버자체 메일서버로 메일보내버려도 정상발송되어 포털사이트에 스팸메일함도 아닌 받은메일함에 당당하게 자리하고 있던데요....? 어떻게 된 거죠????
-
mail() 함수가 아니라 sendmail을 통해 보내서 그런가보죠. 메일에 제목, 메시지 말고도 여러 기준의 포멧이 있는데 잘 지켜졌는가를 각 포탈들이 보고 대응하는 것 같습니다. 국내 광랜은 대부분 공인IP를 DHCP로 돌려가며 사용하고 있는걸로 아는데 사설도 많은가보군요.
-
snows96
2011.11.07 00:36
아, 광랜 자체가 공인IP이군요... 전 유동IP처럼 가정인터넷 자체가 사설인 줄 알았는데.... 무조건 고정IP만 공인이라 생각하고...... (하긴, 유동IP더라도 받았던 IP주소 그대로 바뀌기 전에 외부에서 치면 접속되는 걸 보아선.....) 단, 인터넷선 공유해서 PC가 여러대 물려있는데 서버만 특별히 DMZ설정을 해 놓아서 외부에서 받은게 공인인거라면 공인받은거나 다름없죠.
저의 경우에는 sendmail 설치되어있고 XE코어에서 자체적으로 보내는 E-mail(메일인증, 비번찾기)을 테스트 하였는데 그럼 XE는 서버에 설치된 메일 서버를 통해 보내는건가요? (예전에 메일서버 없을 때 발송안되었던 기억으론...) 그리고 어떤 외부모듈 중에는 또 mail()이라는 함수를 쓰는게 있나 보군요.....
-
Hide_D
2011.11.03 22:39
아뇨 사설 IP는
192.168.*.*로 주로 공유기를 사용하는 가정에서 흔히 볼 수 있는 주소를 말합니다.
-
snows96
2011.11.07 00:38
그렇군요..... 라르게덴님께서도 광랜은 DHCP로 "공인IP"를 돌려가며 사용하는 것일거라고 해놓으셨더군요...... 전 고정IP아니면 (유동이면)다 사설인 줄 알았습니다. ㅎㅎ
물론 집에서 공유기를 사용하여 PC여러대를 몰려놓지만 서버에 DMZ설정을 해놓아서 외부IP가 공인이라면 서버는 공인IP사용하는거나 마찬가지죠 ㅎㅎ
중요한건 ssl 모듈이 로드되어야한다는것..