'대량메일'에 해당하는 글 1건

제가 올리는 팁이 항상 그렇듯이...
실력 좋은 분들은 패쓰해야 하는 허접한 팁입니다.
그점 감안하고 봐 주세요 ^^;;

일반적으로 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)



위와 같은 소스로 메일을 발송하다보면... 중간에... 다음과 같은 에러가 발생한다



커넥션이 끊어졌다는 것이다. -.-;;
바로 업체 정보를 가져오는 $sComQuery를 실행할 수 없어서 에러가 난 것이다.
그러면서 그 이후의 메일 발송은 바로 stop이 되는 난감한 상태가 발생한 것이다.
그렇다고 해서 connection 타임을 mysql 설정 단에서 늘려주면, 일반 웹서비스로 인해 디비커넥션이 full 되서 디비서버 자체가 죽을 우려가 있었기 때문이다.

조금의 고민 끝에... 커넥션이 끊어 졌으면 pconnect를 써야 겠다 라는 생각에 클래스를 pconnect로 접속하도록 바꿨지만, 이 역시 마찬가지 결과를 가져왔다.

그래서 결국에는 '커넥션 끊어지면, 다시 커넥션 하면 되지 뭐 -.-;;' 라는 생각에...
is_resource 함수를 사용하기로 했다 ^^;;

******* 바꾼 소스... ************


그런데... 다시 생각해 보니 $conn은 원래부터가 resource가 아니였던 것이다. -.-;;
메뉴얼에도 잘 나와 있다시피...



처럼 접속 했을 때 $db_link가 resource인 것이지, new를 통해 생성한 객체는 object 였던 것이다 -.-;;

그래서 결국에는 class에 메쏘드 하나를 추가하기로 했다. -.-;;




그리고 나서 위에 소스도 다음과 같이 수정했다.

******* 최종 소스... *********


아직까지는 잘 돌아가고 있으며, 메일 10만통을 보내는 데 1시간 정도 걸린다.(물론 콘솔을 4개 띄워서 동시에 4개의 프로세스로 돌린 경우이다 ^^;;)
php로 한시간 정도 에러 안나고 돌아가면... 성공한 것 아닌가? ㅋㅋㅋ

어째든... 아무런 에러 없이 계속 돌아가 주기만을 바랄뿐이다 ^^
신고

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글  9개가 달렸습니다.
  1. is_resource 함수 필요 없네요 -.-;;
    역시나 에러 발생합니다.
    그래서 무조건 커넥션 다시 맺게끔 하고 테스트 해 봤더니, 기존에 커넥션 맺어져 있으면, 다시 안맺네요... ㅋ
    끊어 졌을 경우에만 다시 커넥션을 생성하구요...
    그래서 무조건 커넥션 맺도록 수정했습니다. ^^
  2. 저라면 상단에 메일연락처를 별도파일로 작성한후에 해당 파일을 읽으면서 내용수정하고 메일발송하고 발송결과를 해당파일이나 연관파일에 업데이트 하는 방식을 사용하겠습니다.
  3. 똥파리//이미 스쿨에서 그런 내용들이 나왔는데... 그냥 이전 블로그 폭파되서 다시 올려놓은 팁이에요 ^^
    다시 하게 된다면... 좀더 잘 하게 되겠죠 ㅎㅎ
  4. 비밀댓글입니다
  5. 좋은글 잘 읽었습니다^^
    php를 binary 버전으로 컴파일 한 후 콘솔에서 실행시킨다는 게 어떤건지 궁금합니다. 제가 php입문한지 얼마 안되어서요. 좀 자세히 알려 주실 수 있으실련지요?^^
    • 요즘은 그냥 리눅스에서 설치하면 실치 디렉토리 안에 php 실행 파일이 있더군요.
      고놈을 쉘 실행시키듯이 실행하면 됩니다.
      구글링 해보면 많이 나옵니다 ^^
  6. 포스팅 되어 있는 다중연결 소켓에 나오는 방법을 말씀하시는 거죠?^^
    #!/usr/local/bin/php -q
secret