강의 컨설팅 트레이닝 무료진단 무료책자 마케팅편지 마케팅정보공유 다이어리 서비스제휴 고객센터

대량 메일 발송 소스 (PHP 강좌/PHP 사용팁)
작성자 : 13 김영철
등록날짜 : 2009.01.13 14:39
4,950
일반적으로 php 프로그래밍은 길어봐야 수초 내에 끝나는 것이 대부분이다. 
  하지만, 메일을 보낸다거나 할 경우에는 소스 상단에 set_time_limit(0); 를 추가해서 보내는 경우가 있다. 
  물론 돈이 많거나, 실력이 뛰어난 프로그래머라면, 좋은 발송기를 사거나, 좋은 프로그램을 짜서 보내면 되지만, 
  나와 같이 허접한 실력의 프로그래머라면, php로 해결하는 수 밖에 없다 ^^;;; 
  
  보통의 경우... 대량 메일을 보내기 위해서는 서버단 설정을 먼저해야 한다. 
  요즘 나오는 센드메일은 멀티 큐를 지원하고 있고, 큐메일은 예전부터 멀티큐를 지원하기 때문에, 
  메일 서버 자체에서는 별로 설정할 일이 없다. 
  만일 메일 서버단의 설정이 궁금하다면, 멀티큐로 검색해 보면 많이 나올 것이다. 
  
  오늘 여기서 다루고자 하는 것은... 
  php 프로그램으로 대량 메일을 어떻게 보내야지만 좋을까 하는 것이다. 
  사장님의 압력에 몇번의 실패 끝에 알아내게 된 내용을 적어본다. 
  
  1. rcpt to를 이용한 방법 
  
  처음에 선임자가 짜 놓은 프로그램을 보니 smtp class를 이용해서 보내는 것이었다. 
  그런데 10만통을 5분에 쏜다고 사장님께서 말씀하시길래 이해가 안가서 소스를 뒤적여 봤더니... 
  헤더를 조작해서 보내는 것이었다 -.-;; 
  즉 메일의 rcpt to에다가 
  
  aaa@hanmail.com,bbb@hanmail.com,ccc@hanmail.com...........zzz@naver.com 
  
  이런식으로 해 놓고, 헤더의 receive에는 그냥 '회원님' 하고 보내는 것이었다. 
  
  그러면 받는 사람한테는 rcpt to의 내용이 보이지도 않으면서, php 프로그램 상에서는 메일을 한통만 쏘는 효과가 있었던 것이었다 -.-;; 
  물론... 센드메일이나 큐메일은 rcpt to에 콤마로 이어놓은 메일 수 만큼 bacrground로 열심히 메일을 뿌리고 있겠지만... ^^;; 
  
  하지만 이 방법의 문제점은 header의 to 정보와 rcpt to의 to 정보가 불일치 하기때문에, 
  대부분의 메일서버가 스팸으로 분류한다는 단점이 있다 -.-;; 
  결국 보내봐야 소용없는 메일이 되고 만다 -.-;; 
  따라서 다른 방법을 찾아봐야만 했다. 
  
  2. smtp로 직접 접속해서 보내는 방법 
  
  smtp로 보내는 방법은 여러가지 설정화 헤더 정보 등을 임의로 입맛에 맞게끔 수정해서 보낼 수 있다. 
  하지만, 브라우져라면 한번에 한 창을, 실행파일이라면 한번에 한 프로세스만을 띠울 수 밖에 없다. 
  smtp 프로토콜을 이미 하나의 프로세스가 잡고 있기에, 다른 프로세스는 대기할 수 밖에 없기 때문이다. 
  따라서 php의 mail() 함수를 사용해서, smtp를 물고 있지 않더라도, MTU에 그냥 메일만 던져주고 빠지는 방식을 쓸 수 밖에 없었다. 
  
  3. 콘솔 상에서 보내는 방법 
  
  보통 브라우져로 메일을 보내게 되면, 브라우져=>아파치=>php=>MTU 의 단계를 거치게 된다. 
  또한 브라우져는 http 통신을 하게 되므로 지속적인 연결을 하면서 메일을 발송하는 것에는 조금 불안한 감이 있다. 
  따라서 php를 binary 버전으로 컴파일 한 후... 아파치와는 독립적으로, perl이나 sh 파일처럼 콘솔 상에서 직접 실행함으로서 조금은 안정적으로 보낼 수 있다. 
  
  * 문제점 
  
  본인의 경우에는 업체명을 쿼리한 후... 해당 업체에 소속된 회원에게 메일을 발송하는 작업이었다. 
  메일을 보내는 헤더정보와 메일 내용의 footer 부분에 해당 업체의 정보가 들어가야 하기에 루푸문 안의 쿼리는 어쩔 수 없었다. 
  
  업체의 정보와, 회원의 메일 정보를 가져오는 디비쿼리의 경우에는 메일을 보내는 동안 디비 커넥션을 계속 물고 있어야 하기에, 
  디비 클래스를 조금 수정하여, 해당 정보를 배열로 받고 난 후 접속을 끊어 버리는 형태로 만들었다. 
  하지만, 이 또한 문제점이 발생하였다. 
  
  ex) 
  
  $conn= new mysqlClass('호스트', '디비병', '유저명', '패스워드'); 
  
  //회원정보 불러오기... 
  $sListQuery = "SELECT index, email, company_id FROM email_list WHERE ORDER BY company_id ASC LIMIT ".$argv[5].", ".$argv[6]; 
  $aListRows = $conn->getData($sListQuery); 
  
  if(is_array($aListRows)) { 
      foreach($aListRows AS $key=>$value) { 
          //업체 정보가 틀려 졌다면... 
          if($aListRows[$key]['company_id'] != $aListRows[$key-1]['company_id']) { 
              //업체 정보 쿼리 
              $sComQuery = " 
                  SELECT 
                      A.ID, A.Name, A.Email, 
                      B.Company, B.Addr, B.Phone, B.Fax, B.Homepage, B.NickName 
                  FROM MemberOfCompany AS B 
                  LEFT JOIN Member AS A ON A.id=B.id 
                  WHERE A.ID='".$aListRows[$key]['company_id']."'"; 
              $aComRows = $conn->getData($sComQuery, 1); 
  
              //메일 header 생성 
  
              //메일 body 생성 
          } 
  
          if(($bResult = mail($aListRows[$key]['email'], $argv[4], $body, $headers)) == 1) { 
              echo "Send OK, ".$aListRows[$key]['index'].", ${NickName}사무실, Sucess Count - $i, Sucess Email - ".$aListRows[$key]['email']."\n"; 
              $i++; 
          } 
          else { 
              echo "Send Error : ".$aListRows[$key]['index'].", ${NickName}사무실, Failure Email - ".$aListRows[$key]['email']."\n"; 
              exec("echo '".$aComRows['ID'].",".$aListRows[$key]['email']."' >> ".date('Ymd')."_Company.log");    //로그기록... 
          } 
      } 
  } 
  
  
  위와 같은 소스로 메일을 발송하다보면... 중간에... 다음과 같은 에러가 발생한다 
  
  ::2013Lost connection to MySQL server during query2013 
  
  커넥션이 끊어졌다는 것이다. -.-;; 
  바로 업체 정보를 가져오는 $sComQuery를 실행할 수 없어서 에러가 난 것이다. 
  그러면서 그 이후의 메일 발송은 바로 stop이 되는 난감한 상태가 발생한 것이다. 
  그렇다고 해서 connection 타임을 mysql 설정 단에서 늘려주면, 일반 웹서비스로 인해 디비커넥션이 full 되서 디비서버 자체가 죽을 우려가 있었기 때문이다. 
  
  조금의 고민 끝에... 커넥션이 끊어 졌으면 pconnect를 써야 겠다 라는 생각에 클래스를 pconnect로 접속하도록 바꿨지만, 이 역시 마찬가지 결과를 가져왔다. 
  
  그래서 결국에는 '커넥션 끊어지면, 다시 커넥션 하면 되지 뭐 -.-;;' 라는 생각에... 
  is_resource 함수를 사용하기로 했다 ^^;; 
  
  
  *******  바꾼 소스...  ************ 
  if(!is_resource($conn)) $conn= new mysqlClass('호스트', '디비병', '유저명', '패스워드'); 
  
  //업체 정보 쿼리 
  $sComQuery = " 
      SELECT 
          A.ID, A.Name, A.Email, 
          B.Company, B.Addr, B.Phone, B.Fax, B.Homepage, B.NickName 
      FROM MemberOfCompany AS B 
      LEFT JOIN Member AS A ON A.id=B.id 
      WHERE A.ID='".$aListRows[$key]['company_id']."'"; 
  $aComRows = $conn->getData($sComQuery, 1); 
  
  
  그런데... 다시 생각해 보니 $conn은 원래부터가 resource가 아니였던 것이다. -.-;; 
  메뉴얼에도 잘 나와 있다시피... 
  
  $db_link = @mysql_connect('localhost', 'mysql_user', 'mysql_pass'); 
  
  처럼 접속 했을 때 $db_link가 resource인 것이지, new를 통해 생성한 객체는 object 였던 것이다 -.-;; 
  
  그래서 결국에는 class에 메쏘드 하나를 추가하기로 했다. -.-;; 
  
  
  function checkResource() { 
      if(is_resource($this->_CONN)) { 
          return true; 
      } 
      else { 
          return false; 
      } 
  } 
  
  그리고 나서 위에 소스도 다음과 같이 수정했다. 
  
  *******  최종 소스...  ********* 
  if(!$conn->checkResource()) $conn= new mysqlClass('호스트', '디비병', '유저명', '패스워드'); 
  
  //업체 정보 쿼리 
  $sComQuery = " 
      SELECT 
          A.ID, A.Name, A.Email, 
          B.Company, B.Addr, B.Phone, B.Fax, B.Homepage, B.NickName 
      FROM MemberOfCompany AS B 
      LEFT JOIN Member AS A ON A.id=B.id 
      WHERE A.ID='".$aListRows[$key]['company_id']."'"; 
  $aComRows = $conn->getData($sComQuery, 1); 
  
  
  아직까지는 잘 돌아가고 있으며, 메일 10만통을 보내는 데 1시간 정도 걸린다.(물론 콘솔을 4개 띄워서 동시에 4개의 프로세스로 돌린 경우이다 ^^;;) 
  php로 한시간 정도 에러 안나고 돌아가면... 성공한 것 아닌가? ㅋㅋㅋ 
  
  어째든... 아무런 에러 없이 계속 돌아가 주기만을 바랄뿐이다 ^^ 

[출처]  웹디황용

"쇼핑몰·홈페이지·오픈마켓
블로그·페이스북·이메일 등의 각종 마케팅 글쓰기,
각종 광고, 영업, 판매, 제안서, 전단지
반응율 3배×10배 이상 높이는 마법의 8단계 공식"
자세히보기

Comments

번호 제목 글쓴이 날짜 조회
3255 [펌] 제12강 - 방명록 만들기 I M 최고의하루 12.23 5325
3254 팝업창 닫고 프레임이 있는 부모창에서 원하는 페이지로 이동하기 M 최고의하루 12.23 5286
3253 frame, iframe에서 쿠키, 세션 인증(로그인) 처리 안 될 때 해결 방법 13 김영철 01.14 5234
3252 이더넷의 원리 살짝 맛보기 M 최고의하루 12.18 5231
3251 [펌] 제12강 - 방명록 만들기 I M 최고의하루 12.23 5104
3250 [MSSQL] 그룹별 상위 n명 가져오기 예제 13 김영철 01.23 5056
3249 Eclipse에서 ASP 개발하기 M 최고의하루 12.04 5030
3248 XP 네트워크 공유 설정 99 단국강토 01.06 5013
3247 PC 메인보드 콘덴서 교체하기 M 최고의하루 12.18 4987
3246 SQL Server에서 글로벌 변수 구현하기 99 단국강토 12.30 4963
열람중 대량 메일 발송 소스 (PHP 강좌/PHP 사용팁) 13 김영철 01.13 4951
3244 공유기 차단 무력화 시키는 법 99 단국강토 01.13 4943
3243 무료 네비게이션 프로그램 (PC버전) 댓글3 17 vane 12.27 4936
3242 한글 영문변환 참고 문자표 2 아론k 06.24 4918
3241 root에서 mysql db가 안보일때 13 김영철 01.29 4917
3240 내장 그래픽카드 죽이는 법 M 최고의하루 12.04 4875
3239 PC Alarm - 알람 프로그램 댓글1 M 최고의하루 12.04 4852
3238 AJAX 강의 2장 - XMLHttpRequest 오브젝트 사용하기 13 김영철 01.29 4840
3237 html - 테이블에 점선 넣기, 테이블 점선만들기 99 단국강토 02.05 4833
3236 mssql mysql 변환, asp 게시판 소스 수정 13 김영철 01.29 4832
3235 ★★★셀렉트박스 테두리 없애기 99 단국강토 02.04 4829
3234 CSS 사용방법 - 폰트표현 99 단국강토 02.19 4761
3233 데이터베이스의 저장 프로시저를 자동으로 생성 M 최고의하루 12.24 4761
3232 벅스뮤직에 있는 음악 오디오 시디로 만들기 99 단국강토 01.05 4739
3231 mysql함수 [숫자열, 문자열, 집계, 날짜, 기타함수...] 99 단국강토 01.07 4735
3230 윈도우에 설치된 오라클9i 삭제하기 13 김영철 01.29 4621
3229 [ ASP ] 배열 ( Array ) 과 Scripting.Dictionary M 최고의하루 12.20 4620
3228 utf-8 세팅및 한글깨짐방지 M 최고의하루 12.23 4614
3227 [mssql]성능 측정을 위한 설정 13 김영철 01.23 4600
3226 [펌] 제13강 - 방명록 만들기 II M 최고의하루 12.20 4524
마케팅
특별 마케팅자료
다운로드 마케팅자료
창업,경영
기획,카피,상품전략
동기부여,성취