Source for file MTA_Socket.php
Documentation is available at MTA_Socket.php
* Project: MTA_Socket :: MTA socket abstraction layer<br />
* File: MTA/MTA_Socket.php
* eSNMP_Socket class는 소켓으로 메일을 발송하기 위한 추상
* @author JoungKyun.Kim <http://oops.org>
* @copyright (c) 2018, OOPS.org
* @link http://pear.oops.org/package/MTA
* Socket for send mail of MTA API
* 소켓으로 메일을 발송하기 위한 추상 레이어
// {{{ protected MTA_Socket::target_object ($o)
* 동일한 호스트에 여러번 접속하지 않도록 하기 위하여 메일 호스트
* @param stdClass $o mail object
* [to] => (array) to list
* [cc] => (array) cc list
* [bcc] => (array) bcc list
foreach ( $o->to as $ad )
foreach ( $o->cc as $ad )
foreach ( $o->bcc as $ad )
foreach ( $tmp as $addr ) {
if ( $this->check_local ($local, true) == false )
if ( $this->check_domain ($host, true) == false )
if ( ! $target->$host ) {
$target->$host = new stdClass;
if ( getmxrr ($host, $mx, $weight) ) {
foreach ( $weight as $key => $val ) {
$target->$host->mx[] = $val . ' ' . $mx[$key];
sort ($target->$host->mx, SORT_NUMERIC);
$target->$host->mx = array ('10 ' . $host);
$target->$host->rcpt[] = '<' . $mail . '>';
// {{{ (object) protected MTA_Socket::socket_send ($o, &$template)
* @return stdClass 발송 결과를 object로 반환한다.
* [status] => (boolean) 성공 실패 여부
* [error] => (string|null) status false시 에러 메시지
* [rcptlog] => (array) rcpt to에 대한 log
* RCPT list별로 확인을 위해서 status가 true이더라도 rcptlog를
* @param stdClass $o mail object
* [rpath] => (string) return path (optional)
* [from] => (string) Sender address
* [to] => (array) Reciever address
* [cc] => (array) See also reciever address
* [bcc] => (array) Hidden see also reciever address
* [subjet] => (string) mail subject
* [body] => (string) mail contents
* [pbody] => (string) planin/text mail contents (optional)
* [attach] => (array) attached files (optional)
* @param string &$template 메일 본문
foreach ( $t as $vendor => $val ) {
$this->debug ('Trying to ' . $vendor);
$r->$vendor = new stdClass;
if ( $this->open ($val) === false ) {
$r->$vendor->status = false;
$r->$vendor->error = $this->error;
if ( $this->ehlo () === false ) {
$r->$vendor->status = false;
$r->$vendor->error = $this->error;
$r->$vendor->status = false;
$r->$vendor->error = $this->error;
if ( $this->rcptto ($val, $log) === false ) {
$r->$vendor->status = false;
$r->$vendor->error = $this->error;
$r->$vendor->rcptlog = $log;
$r->$vendor->rcptlog = $log;
if ( $this->data ($template) === false ) {
$r->$vendor->status = false;
$r->$vendor->error = $this->error;
$r->$vendor->status = true;
// {{{ (bool) protected MTA_Socket::ehlo ()
protected function ehlo () {
if ( $this->read () === false )
// {{{ (bool) protected MTA_Socket::mailfrom ($o)
* @param stdClass $o mail object
* - o->from : Sender address
* - o->to : array of Reciever address
* - o->cc : array of See also reciever address
* - o->bcc : array of Hidden see also reciever address
* - o->subjet : mail subject
* - o->body : mail contents
* - o->pbody : planin/text mail contents (optional)
* - o->attach : attached files (array / optional)
$rv = $o->rpath ? $o->rpath : $o->from;
if ( $this->check_local ($chk[0], true) === false ) {
$this->error = 'Invalid local part of Return-Path';
if ( $this->check_domain ($chk[1], true) === false ) {
$this->error = 'Invalid domain part of Return-Path';
$this->write ('MAIL From:<' . $rv . '>');
if ( $this->read () === false )
// {{{ (bool) protected MTA_Socket::rcptto ($o, &$log)
* @param stdClass $o MTA_Socket::target_object method의 rcpt list
* @param array &$log 발송 로그
protected function rcptto ($o, &$log) {
$this->error = 'No RCPT list';
foreach ( $o->rcpt as $addr ) {
$this->write ('RCPT To:' . $addr);
if ( $this->read () === false ) {
$log[] = sprintf ('%s Success', $addr);
$this->error = 'Failure all RCPT list';
// {{{ (bool) protected MTA_Socket::data (&$v)
* DATA 명령 전송 및 mail body 전송
* @param string $v 메일 본문 원본
protected function data (&$v) {
if ( $this->read () === false )
$remote = $_SERVER['REMOTE_ADDR'] ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1';
"Received: from localhost ([{$remote}])\r\n" .
" by {$smtp} with ESMTP id " . uniqid () . ";\r\n" .
' ' . $this->date () . "\r\n";
$this->write ($received . $v . "\r\n.");
if ( $this->read () === false )
// {{{ (bool) protected MTA_Socket::open ($o)
* @param stdClass $o MTA_Socket::target_object method 반환값
protected function open ($o) {
for ( $i= 0; $i< $mxno; $i++ ) {
'tcp://' . $mx . ':25', $errno, $errstr, 3, STREAM_CLIENT_CONNECT
$this->debug (' - Connecting to ' . $mx . '... Success');
if ( ($buf = $this->read ()) === false ) {
$this->debug (' - Connecting to ' . $mx . '... Failure');
// {{{ (string) protected MTA_Socket::read ()
protected function read () {
$buf = fread ($this->sock, 8102);
if ( ! preg_match ('/^(220|221|250|251|354)$/', $code) ) {
// {{{ (int) protected MTA_Socket::write ($m)
* 데이터의 끝에 "\r\n"을 붙여서 전송한다.
* @param string $m 전송할 데이터
protected function write ($m) {
$this->debug (' * ' . $m);
// {{{ (void) protected MTA_Socket::close ()
* Quit 명령을 실행한 후, socket을 닫는다.
protected function close () {
// {{{ (void) protected MTA_Socket::debug ($m)
* verbose properity가 true로 설정이 되면 debug 메시지를
protected function debug ($m) {
echo 'DEBUG: ' . preg_replace ("/\r?\n$/", '', $m) . PHP_EOL;
* vim: set filetype=php noet sw=4 ts=4 fdm=marker:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
|