PHP & Others

메일 보내는 클래스 입니다.

페이지 정보

본문

메일 보내기 클래스

<?php
/*------------------------------------------------------------------------------------------
** mail.inc
**  메일 발송 클래스
** author      : sscmin@hanmail.net
** last modify : 2003. 9. 30
------------------------------------------------------------------------------------------*/
class Mail {

    var $charSet    = "ks_c_5601-1987";                      // 케릭터 셋
    var $binNslookup = "/usr/sbin/nslookup";                  // nslookup 의 경로
    var $defaultHelo = "test.com";                            // HELO 메세지 기본값
    var $boundary    = "PHPmailSender";                      // 기본 boundary
    var $mxCacheDir  = "";                                    // mx 레코드값을 캐싱할 디렉토리
    var $errLogFile  = "";                                    // 에러로그파일의 절대경로 : 파일이 없으면 메시지를 화면에 뿌린다.
    var $relayServer = "";                                    // 릴레이를 이용하려면 릴레이 메일 서버주소
    var $isWindow    = 0;                                    // 윈도우 이면 1
   
    /* mail()
    ** boundary를 만든다.
    */
    function mail() {
            $usec          = time();
            $this->boundary = "----".$usec.".".$this->boundary;
    }

    /* int sendMail
    ** 메일을 발송한다.
    ** parameter
    **  - string $_from : 보내는 사람 메일주소
    **  - string $_name : 보내는 사람 이름
    **  - string $_body : 메일본문
    **  - array  $_to  : 받는 사람 메일주소 (예) $to = array("sscmin@hanmail.net", "minsw@test.com");
    **  - string ($_attach) : 첨부파일이 있는 디렉토리 (예) $attach = "/attach");
    */
    function sendMail($_from, $_name, $subject, $_body, $_to, $_attach = "") {
        $is_attach = $this->mailEncode($_body, $_attach, $mailBody);        // 메일 본문 인코딩
        if ($is_attach) $content_type = "mixed";
        else $content_type = "alternative";
       
        $toCount  = count($_to);
        for ($i = 0; $i < $toCount; $i++) {
                $temp  = explode("@", $_to[$i]);              // 메일서버 주소와 메일 아이디를 구분
                $addr  = $temp[1];
                $header= $this->mkHeader($_from, $_name, $_to[$i], $subject, $content_type);  // mime 헤더 만들기
                $body  = $header.$mailBody;                  // 헤더와 본문을 합친다
                if($this->simpleSend($_from, $_to[$i], $addr, $body)) $retcode[$i] = 1;
                else $retcode[$i] = 0;
            }
            return $retcode;
    }
   
    /* int sendMailonFile
    ** 메일을 발송한다.
    ** parameter
    **  - string $_from : 보내는 사람 메일주소
    **  - string $_name : 보내는 사람 이름
    **  - string $subject : 메일제목
    **  - array  $_to  : 받는 사람 메일주소 (예) $to = array("sscmin@hanmail.net", "minsw@test.com");
    **  - string $filename : 메일 본문 파일
    **  - array  $tpl_value : 메크로 변수
    **  - string ($_attach) : 첨부파일이 있는 디렉토리 (예) $attach = "/attach");
    ** 예) mail.tpl
          --------------------------------------------
          안녕하세요? [MAIL_TPLname]님<br>
          테스트 메일 입니다.<br>
          --------------------------------------------
         
          mail.php
          --------------------------------------------
          <?
          require("mail.inc");
          $mail = new mail();
          $arr_value[name] = $name;
          $to = array("to@test.com");
          $mail->sendMailonFile("from@test.com", "테스트", $to, "$name님께", "mail.tpl", $arr_value);
          ?>
    */
    function sendMailonFile($_from, $_name, $subject, $_to, $filename, $tpl_value = "", $_attach = "") {
            if (!is_file($filename)) {                            // 파일이 존재하지 않을때
                    $this->setError("", "${filename} is not file");
                    return 0;
            }
            if (empty($tpl_value)) {                              // 템플릿 변수가 없을때
                $fp = @fopen($filename, "w");
                    if ($fp) {
                            $body = fread($fp, filesize($filename));            // 파일을 그냥 읽음
                            fclose($fp);
                    } else {
                            $this->setError("", "${filename} can't open file");
                            return 0;
                    }
            } else {                                             
                    $body = $this->changeMacro($filename, $tpl_value); // 메크로를 치환해서 파일을 읽음
            }
            if (!isset($body)) {
                    $this->setError("", "${filename} faild getting body");
                    return 0; 
            }
           
            return $this->sendMail($_from, $_name, $subject, $body, $_to, $_attach); // 메일 센드함수 호출
    }
   
    /* int simpleSend
    ** socket을 이용해 실제로 메일을 발송한다.
    ** parameter
    **  - string $from, string $email_to, string $addr, string $body
    */
    function simpleSend($from, $email_to, $addr, $body) {
            if (isset($this->relayServer)) {
                    $conn = @fsockopen($this->relayServer);
            }
           
            if (!$conn) {
                  /* mx 레코드를 구한다 */
                $mx = $this->getChMx($addr);
                if ($mx) {
                        // 캐시에 저장이 되어있다면
                        $conn = @fsockopen($mx); 
                }
        }
           
            if (!$conn) {
                $mx = $this->getMx($addr);
           
                if ($mx == 0) {
                        /* nslookup을 이용해 mx레코드를 가져오지 못했을 경우 */
                        $this->setError($addr, "Getting Mx Fail");
                        return 0; 
                }
           
                /* mx 배열을 이용해 메일서버에 접속한다 */
                for ($i = 0; $i < count($mx); $i++) {
                        $conn = @fsockopen($mx[$i][2], 25);
                        if ($conn) {
                                $this->addChMx($addr, $mx[$i][2]);    //  접속성공시 캐시를 남긴다
                                break;
                        }
                }
        }

            if ($conn) {
                    /* protocol 을 주고받는 부분 */
                    if(!$this->recvmsg($conn, $recv_buf)) {
                            $this->setError($addr, $recv_buf);
                return 0; 
                    }
                    // HELO
                    $buf = sprintf("HELO %s\\r\\n", $this->defaultHelo);
                    fputs($conn, $buf);
                    if(!$this->recvmsg($conn, $recv_buf)) {
                            $this->setError($addr, $recv_buf);
                return 0; 
                    }               
                    // MAIL FROM
                    $buf = sprintf("MAIL FROM: <%s>\\r\\n", $from);
                    fputs($conn, $buf);
                    if(!$this->recvmsg($conn, $recv_buf)) {
                            $this->setError($addr, $recv_buf);
                return 0; 
                    }
                    // RCPT TO
                    $buf = sprintf("RCPT TO: <%s>\\r\\n", $email_to);
                    fputs($conn, $buf);
                    if(!$this->recvmsg($conn, $recv_buf)) {
                            $this->setError($addr, $recv_buf);
                return 0; 
                    }
                    // DATA
                    fputs($conn, "DATA\\r\\n");
                    $this->recvmsg($conn, $recv_buf);
                    $buf = sprintf("%s\\r\\n.\\r\\n", $body);
                    fputs($conn, $buf);
                    if(!$this->recvmsg($conn, $recv_buf)) {
                            $this->setError($addr, $recv_buf);
                return 0; 
                    }
                    // QUIT
                fputs($conn, "QUIT\\r\\n");
                $this->recvmsg($conn, $recv_buf);
               
                fclose($conn);
                return 1;
            } else {
                    /* 컨넥팅 실패 */
                    $this->setError($addr, "Connecting Fail");
                    return 0;
            }
    }
   
    /* string mkHeader
    ** 헤더를 만든다.
    */
    function mkHeader($from, $name, $to, $subject, $content_type) {
            if ($name)
                $header = "From: \\"=?$this->charSet?B?".base64_encode($name)."?=\\" <${from}>\\r\\n";
            else
                $header = "From: <${from}>\\r\\n";
        $header.= "To: <${to}>\\r\\n";
        $header.= "Subject: =?$this->charSet?B?".base64_encode($subject)."?=\\r\\n";
        $header.= "Errors-To: <${to}>\\r\\n";
        $header.= "Content-Type: multipart/$content_type; boundary=\\"$this->boundary\\"\\r\\n\\r\\n";
        return $header;
    }
   
   
    function addChMx($addr, $mx) {
            if (is_dir($this->mxCacheDir)) {
                $fp = @fopen($this->mxCacheDir."/".$addr, "w");
                @fputs($fp, $mx);
            @fclose($fp);
        }
    }
   
   
    function getChMx($addr) {
            if (is_dir($this->mxCacheDir)) {

            $dirp = @opendir($this->mxCacheDir);
                    while ($filename = readdir($dirp)) {
                if ($filename == $addr) {
                    $line = @file($this->mxCacheDir."/".$filename);
                            }
                    }
            if ($line[0]) $return = $line[0];
            else $return = 0;

      } else $return = 0;
     
      return $return;
    }
   
    /* string mailEncode
    ** 첨부파일을 읽어 본문을 만든다.
    */
    function mailEncode($body, $attach, &$mailBody) {
            $message = "--".$this->boundary."\\r\\n";
            $message.= "Content-Type: text/html; charset=$this->charSet\\r\\n";
        $message.= "Content-Transfer-Encoding: base64\\r\\n\\r\\n";
        $message.= ereg_replace("(.{80})", "\\\\1\\r\\n", base64_encode($body))."\\r\\n";
            if (is_dir($attach)) {
                    $dirp = opendir($attach);
                    while ( $filename = readdir($dirp) ) {
                            if ($filename != "." && $filename != "..") {
                                    $fp = @fopen($attach."/".$filename, "r");
                                    if( $fp ) {
                                            $content = fread($fp, filesize($attach."/".$filename));
                                $message_attach.= "\\r\\n--".$this->boundary."\\r\\n";
                                $message_attach.= "Content-Type: unknown; name=\\"=?$this->charSet?B?".base64_encode($filename)."?=\\"\\r\\n";
                        $message_attach.= "Content-Transfer-Encoding: base64\\r\\n";
                        $message_attach.= ereg_replace("(.{80})", "\\\\1\\r\\n", base64_encode($content))."\\r\\n";
                        fclose($fp);
                    }
                }
            }
            }
           
            $mailBody = $message.$message_attach;
            if (empty($message_attach)) return 0;
            else return 1;
           
    }
   
    /* getMx
    ** 호스명을 받아 nslookup을 이용해 mx 레코드를 구한다.
    ** parameter : string $host - 도메인명
    ** return    : success - array(array()) $ret
                            $ret[$i][0] 우선순위
                            $ret[$i][1] 호스트명
                            $ret[$i][2] ip주소
                  fail    - int 0
    */
    function getMx($host) {
            $command = "$this->binNslookup -type=mx ${host}";
        @exec ( $command, $result );  // nslookup 실행
        if ($isWindow) $nTemp = 1;

        $i = 0;
        while ( list ( $key, $value ) = each ( $result ) ) {
            if ( strstr ( $value, "mail exchanger" ) ) { $nslookup[$i] = $value; $i++; }
        }
       
        if ($i > 0) { 
            while ( list ( $key, $value ) = each ( $nslookup ) ) {
                $temp = explode ( " ", $value );
                $mx[$key][0] = $temp[2+$nTemp];                            // 우선순위
                $mx[$key][1] = $temp[6+$nTemp];                            // host name
                $mx[$key][2] = gethostbyname ( $temp[6+$nTemp] );          // ip address
            }
            array_multisort ( $mx );    // 정렬
        } else
            $mx = 0;                    // 검색값이 없을경우 0을 리턴
           
        return $mx;
    }
   
    /* int recvMsg
    ** 소켓에서 메시지를 받아 성공여부를 리턴한다.
    */
    function recvMsg($conn, &$recv_buf) {
            $ok_code = array("220", "250", "354", "221");
            $recv_buf = fgets($conn, 1024);
            for ($i = 0; $i < 4; $i++) {
                if (substr($recv_buf, 0, 3) == $ok_code[$i])
                        return 1;
        }
        return 0;
    }
   
    /* string changeMacro
    ** parameter : stiring $file    (템플릿파일 경로)
    **            array  $tpl_var (템플릿 변수)
    ** return    : string $value    (치환이 완료된 파일의 문자열)
    ** 파일을 읽어 변수로 받은 문자열과 비교, 치환한다
    */
    function changeMacro($file, $tpl_var)
    {
        $line = file($file);                                  // 파일을 라인단위로 읽어 배열에 저장
        while(list($key,$val) = each($line)) {                // 파일을 읽은 배열을 key와 value로 분리
            if(strpos($val, "MAIL_TPL") > 0) $val = $this->changeLine($val, $tpl_var); // MACRO_V를 포함한 라인이면 치환
            $value .= $val;
        }
        return $value;
    }

    /* string changeLine
    ** 첫번째 인자로 받은 문자열중 두번째 인자로 받은 배열의 key와 일치하는 문자열을,
    ** 두번째 인자로 받은 value로 치환하고, 치환된 문자열을 리턴.
    */
    function changeLine($value, $tpl_var)
    {
        while(list($key,$val) = each($tpl_var))              // 메크로 변수를 key와 value로 분리
            if (!(empty($key))) $value = str_replace("[MAIL_TPL$key]", "$val", $value); // $value중 $key와 일치하는 부분을 $var로 치환
        return $value;
    }
   
    /* void setError(string $msg)
    ** 로그를 기록한다.
    */
    function setError($addr, $msg) {
            if (isset($this->errLogFile)) {
            if ($fp = @fopen($this->errLogFile, "a")) {
                $msgTemp = sprintf("[%04d/%02d/%02d %02d:%02d:%02d %s ] ",
                            date("Y"), date("m"), date("d"), date("H"), date("i"), date("s"), $addr);
                $msgTemp = $msgTemp.$msg."\\r\\n";
                fputs($fp, $msgTemp);
            } else {
                    echo $msg; 
            }
        }
    }
   
    /* void exitError(string $msg)
    ** 에러 메시지를 출력하고 스크립트를 종료한다
    */
    function exitError($msg) {
            echo "Error: $msg<br>";
            exit(); 
    }
}

?>

 

 
mail() 함수를 사용할수 있는 여건이라면... mail()함수를 사용하는게 편하겠지만........일단 mail()함수의 리턴값만으로 메일이 갔는지를 확신할수 없고, 어디에서 어떻게 에러가 나는지도 확인하기가 어렵습니다.

관련자료

등록된 댓글이 없습니다.
Today's proverb
인내심을 가져라. 때가 되면 모든 것은 변한다. 조바심이 가을의 영광을 만들거나 살을 에는 겨울을 끝낼 수 는 없다. 근심을 오랫동안 마음에 품고 있으면 그만큼 마음의 평정을 회복하기 어려워진다. 나쁜 생각을 스스로 떨쳐버려라. 나쁜 생각은 영혼의 뿌리를 갉아먹는 악이다.