홈으로 홈으로 | 무료회원가입 | 아이디/비번찾기 | 즐겨찾기
추천음악방송메인홈1대1상담음악방송청취
아리랑가요(무료음악채널)
뽕짝아가씨(무료음악채널)
okTrot(무료음악채널)
전통가요(무료음악채널)
미스트롯(무료음악채널)

온라이브스토어(앱다운로드)

환상의뽕짝파티 무료음악
명작트로트메들리 무료음악
트로트메들리관광 무료음악
동영상노래방
가사검색

POP Player
신나는 고스톱
컴퓨터 오목
작은 음악다방
자동러시 웹플레이어신청

보안∵서버∵쿠키
윈도우∵프레임
이미지∵배경
시간∵달력∵계산
상태바∵타이틀바
음악∵영상
폼∵전송∵테이블
키보드∵마우스
효과∵링크∵메뉴
Script∵php
기타
PHP 강좌
윈도우관련팁
웹관련팁
홈페이지제작팁
기본강좌
레지스트리
윈도우서버
리눅스서버
Android
대량 메일 발송 소스
7년 전
일반적으로 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);
추천추천 : 467 추천 목록
번호 제목
3,020
 [HTML5] <video> - DOM으로 제어하기
3,019
 HTML5 video 태그에서 영상 좌우반전
3,018
 PHP - 특정 태그 및 문자열 추출, 제거
3,017
 [PHP] define과 defined의 차이
3,016
 우클릭 완벽차단 스크립트
3,015
 iframe 높이 100% 맞추기
3,014
 curl 함수를 이용한 HTTP REFERER 변경
3,013
 윈도우10 시스템 파일 및 Dism 검사
3,012
 텍스트 줄바꿈, 글자자르기 CSS
3,011
 jQuery Mobile에서 유용한 코드 10가지.
3,010
 [PHP] dirname()함수와 $_SERVER 관련 상수들
3,009
 [PHP] 파일 크기, 사이즈 불러오는 함수, filesize()
3,008
 [jQuery] jQuery Quick API
3,007
 [ transition ] 링크 hover 색상 변화 속도 조절
3,006
 PHP 5.3.0 에서 사라진 함수들 대체
3,005
 어떤 파일들이 include 나 require 되었는지 확인하는 함수(get_included_files)
3,004
 PHP 날짜 형식 및 계산하기(날짜 더하고 빼기)
3,003
 jQuery Mobile에서 유용한 코드 10가지.
3,002
 값이 배열 안에 존재하는지 확인하는 in_array함수
3,001
 사용자가 웹브라우저에서 뒤로가기를 했을때 감지하는 방법
3,000
 [jQuery]버튼 활성화, 비활성화
2,999
 jQuery show() / hide() / toggle() 사용법
2,998
 jquery 여러가지 이벤트
2,997
 border-radius 속성
2,996
 네이버 오픈API 음성합성 API 사용하는 PHP 샘플코드
2,995
 UTF8 한글 자르기..
2,994
 iconv 에러 발생시 계속 처리하기 옵션
2,993
 [PHP] 현재 페이지의 도메인 , URL 정보 알아내기.
2,992
 [PHP] 막강 기능 배열..
2,991
 [CSS] - Input clear `X ` 버튼 제거 ( IE, Chrome, Firefox )
2,990
 [Mobile] - 모바일웹 Href 태그속성들
2,989
 [JqueryMobile] - 현재화면의 가로세로 사이즈 구하기
2,988
 [JqueryMobile] - 화면의 가로, 세로 사이즈 구하는 방법
2,987
 jquery로 가로 넓이(width), 세로 높이(height) 자동 조절
2,986
 iframe 높이 jquery로 자동조절하기
목록
추억의가요방(가사포함)
인기절정뽕짝파티
인기트로트모음
지루박디스코메들리
밤무대애창곡
전자올겐경음악
세월따라노래따라
가슴시린트로트
트로트쌍쌍파티
7080추억속으로
종합성인가요방
못잊을옛날노래
카바레 음악
트롯디스코팡팡
관광 메들리
트롯카페
가요감상실
추억의옛노래
스페셜가요광장
BillBoard Free
추천가요모음
경음악.전자올겐
스페셜음악여행
WOLRD POPs
K-POP\BillBoard
POP TOP BEST

최신인기가요특집
추천가요\인기
F뮤직 인기\발라드
F뮤직 애창\트로트
트로트성인가요
인기가요
프리미엄 POP
경음악\기타
프리미엄 최신가요
프리미엄 성인가요
가요축제\트롯1번지
댄스\메들리\리믹스
카페\명상\경음악\기타
뮤직트로트 부산광역시부산진구 가야동 ㅣ 개인정보취급방침
Copyright (C) musictrot All rights reserved.