웹마스터 팁

들어가기전에

오랜만에 팁을 올려봅니다. 해당 팁은 기존 XE Core에서 이용되는 mail()함수를 통한 이용방법이 아닌 별도의 SMTP 서버를 이용하여 전송할 수 있도록 해주는 팁 입니다.

XE mail과 다른점

기존 방식에 문제점은 mail()를 이용하기 때문에 메일이 도착하지 못하는 경우가 발생하고 외부메일을 이용한 방식이 불가하다는 점 입니다. 이를 개선하여 어디든 도착가능 하도록하고 외부메일(gmail 등)의 SSL 인증 방식을 통해 서버내에 메일이 동작하지 않더라도 타 기관의 SMTP 서버를 통해 메일을 보낼 수 있습니다.

주의점

- 앞으로 설명할 내용은 개발자용의 소스인지라 일반인들이 적용하기엔 무리가 따를 수 있습니다.

- mail()가 아닌 fsockopen() 방식을 사용합니다. 본인의 호스팅이 각 기관(예 gmail) 경로로의 접근이 막혀있다면 외부경로로 하셔도 접근이 안되실 수 있습니다.
- 사설 ip의 경우 본인 컴에 sendmail 등을 올려도 메일발송이 안될 수가 있습니다.



소스

/**
 * @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';
}


수행

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을 올려도 되질 못하여 내놓을 수 없다가 이번에 되는걸 확인하고 팁으로 적어보았습니다. 설명도 부족하고 개발자들이 보셔도 잘 사용할지 못할지 모르겠지만 위와 같은 형식으로 사용하시면 기존에 메일을 발송해도 못받으시거나 하던 문제는 해결 됩니다.


나중에 따로 배포본으로 만들어서 자료실에 올리던가 해야겠습니다. 하지만 위 기능하나만 가지고 내는건 뭐해서 제가 제작하는 모듈에 알림이 기능으로써 각각 집어넣을지 단체메일링 같은 좀 살을 붙여서 모듈로 배포할지는 고민중입니다.

태그 연관 글
  1. [2016/10/17] 묻고답하기 https 관련 질문입니다 ㅠㅠ by 쿠닌 *1
  2. [2016/04/26] 묻고답하기 회원가입(휴대폰인증모듈)페이지 속도 문제.. by deok *3
  3. [2016/04/13] 웹마스터 팁 IIS에서 HTTPS를 사용하기 위한 SSL설정 (letsencrypt 인증서 설치, 갱신) by ehii
  4. [2016/03/18] 묻고답하기 SSL 테스트, B등급에서 더 올릴 수 있나요? by 마꼬꼬 *2
  5. [2016/01/07] 묻고답하기 ssl 항상사용 후 접근이 안되고 있습니다.. by 신다영 *5
제목 글쓴이 날짜
외부페이지를 레이아웃에 결합시 상단 마진폭이 벌어지는 문제 해결방법 [6] file DuRi 2010.12.17
1.4.2.3 에서 1.4.3 이상 버전으로 업그레이드 시 백지화면 해결팁 [4] 2년후 2010.12.15
메인화면에 설문조사 위젯(?) 만들기 [3] file 3D매니아 2010.12.14
[생초보팁] 레이아웃 수정시 HTML 넣는 칸 넓히기 -_- 에혀라X 2010.12.12
[생초보팁] 웹진최근게시물 요약글 링크걸기 [1] file 에혀라X 2010.12.12
[생초보팁] 페이지(page) 줄간격과 부분 웹폰트 에혀라X 2010.12.11
사이트 모니터링 알리미에요...^^ [3] file web 2010.12.10
플래시로 만들어진 글자 타이핑보고 만들었어요. web 2010.12.09
ftp나 mysql 암호 변경시 일어나는 ''db 접속시 에러' XE 샷타이거 2010.12.08
어느게시판이든 모두 적용이 가능한 그림판입니다.^^ [1] web 2010.12.07
새로운 채팅 서비스 웹톡! [3] file 명랑폐인™ 2010.12.06
[생초보팁] 회원가입시 홈페이지 블로그주소 않나타내기 ㅋ [4] 에혀라X 2010.12.05
호스팅비 돈아낍시다. 하나의 XE 다중 도메인 사용하기. [10] kimnada 2010.12.02
[생초보팁] 페이지 내용 줄간격 css 에혀라X 2010.11.30
최근문서 or 콘텐츠 위젯 공지글 뽑아오기 [8] Xiso 2010.11.29
게시물 하단에 예쁜 추천,비추천 아이콘 버튼 추가하기~ [12] file xemall 2010.11.28
텍스타일 (Textyle) 에서 첨부파일 용량 제한 늘리는 방법. [1] sejin7940 2010.11.27
개인 홈페이지에서 아주 손쉽게 배경음악을 깔아놓는 법 [5] 지녁 2010.11.25
[생초보팁] 서브메뉴 배경이미지 활용하기 [4] file 에혀라X 2010.11.24
앞으로 공용선택자 사용은 그만.... [5] ForHanbi 2010.11.23