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
슬픔과 아무것도 없는 것 중 하나를 택하라면 나는 슬픔을 선택할 것이다. (W.포크너)