プロが教える店舗&オフィスのセキュリティ対策術

目的:
phpにて、添付付きメールを、件名だけ変更して、添付ファイルごと外部へ転送する。

現在、メール受信したものを、mysqlに保存(UID、件名、送信元メールアドレス(一致したものを、指定の件名に変更)、送信日、受信日、本文)、
添付ファイルはサーバー上に保存し、

メール送信時に、サーバー上に保存した添付ファイルとmysqlのデータを読み込み、送信しています。
(添付ファイルは、定期的に削除)

これを、もっと簡潔に出来ないでしょうか。
サーバー上に添付ファイルを残さないで済み、
未受信のメールのみ
1画面上で、添付メールごと転送できるのが理想です。
※mysqlへの保存は、あってもなくてもかまいません。

以下が、現在の状態です。

参考にしたのは、こちらのサイトです。
http://hal456.net/qdmail_rec/top
http://www.favorite-labo.org/view/202

※サーバはCPIです。


**メール受信処理**
<?php

// QdmailReceiver呼び出し
require_once('qdmail_receiver.php');

//POPサーバー(受信サーバー)にアクセスするための初期設定。
$server = array(
'protocol'=>'pop3',
'host'=>'(ホスト名)',
'user'=>'(ユーザー名)',
'pass'=>'(パスワード)',
);
qd_receive_mail( 'start' , $server , 'eucJP-win' );

//オブジェクト指向モードでの初期化
$receiver = QdmailReceiver::start( 'pop' , $server);

for($i = 1 ; $i <= $receiver->count() ; $i++){

$todaydata = date("Y-m-d");
// *************** メールデータ取得処理 ***************
$pointer = $receiver->pointer();// pointer
$popuid = $receiver -> header( 'popuid' );// UID
$subject_name = mb_convert_encoding(($receiver->header( array('subject','name') , 'none' )),"Shift-JIS","auto");//件名
$from_mail = $receiver->header( array('from','mail') , 'none');//送信元メールアドレス
$date = $receiver -> header('date');//送信日
$text = mb_convert_encoding(($receiver->text()),"Shift-JIS","auto");//本文

// *************** UID照合処理 ***************
include '(mysql接続)';


$ii=0;
while ($row = mysql_fetch_assoc($result)) {
$ii++;
}

if($ii == 0){
// *************** 転送前データの保存 ***************
include '(mysql接続)';

// *************** 添付ファイル保存 ***************

$attach = $receiver->attach();
foreach($attach as $att){
  $moji = mb_convert_encoding($att['filename'],"Shift-JIS","auto");
$fp=fopen($moji,'w');
fputs($fp,$att['value']);
fclose($fp);
}

}else{
print('取得済みにつき未処理');
}
?>

**メール送信**
<?php

//マイムタイプ定義
$mime_content_types = array(
'ez' => 'application/andrew-inset',
'atom' => 'application/atom+xml',
'atomcat' => 'application/atomcat+xml',
~略~
'avi' => 'video/x-msvideo',
'movie' => 'video/x-sgi-movie',
'ice' => 'x-conference/x-cooltalk'
);

//送信先メールアドレス
$to = '(送信先メールアドレス)';

//送信元メールアドレス
$from = '(取得した送信元メールアドレス)';

//件名
$subject = '(変更した件名)';

//メール本文
$message = (取得した本文);


//添付ファイル
$files = array('(添付ファイル1へのパス)','(添付ファイル2へのパス)…以下、あるだけ');

//件名・本文をエンコード
$subject = mb_convert_encoding($subject, 'JIS', 'Shift-JIS');
$message = mb_convert_encoding($message, 'JIS', 'Shift-JIS');

$subject = '=?iso-2022-jp?B?' . base64_encode($subject) . '?=';

//バウンダリ文字列を定義
if (empty($files)) {
$boundary = null;
} else {
$boundary = md5(uniqid(rand(), true));
}

//メールボディを定義
if (empty($files)) {
$body = $message;
} else {
$body = "--$boundary\n";
$body .= "Content-Type: text/plain; charset=\"iso-2022-jp\"\n";
$body .= "Content-Transfer-Encoding: 7bit\n";
$body .= "\n";
$body .= "$message\n";

foreach($files as $file) {
if (!file_exists($file)) {
continue;
}

$info = pathinfo($file);
$content = $mime_content_types[$info['extension']];

$filename = basename($file);

$body .= "\n";
$body .= "--$boundary\n";
$body .= "Content-Type: $content; name=\"$filename\"\n";
$body .= "Content-Disposition: attachment; filename=\"$filename\"\n";
$body .= "Content-Transfer-Encoding: base64\n";
$body .= "\n";
$body .= chunk_split(base64_encode(file_get_contents($file))) . "\n";
}

$body .= '--' . $boundary . '--';
}

//メールヘッダを定義
$header = "X-Mailer: PHP5\n";
$header .= "From: $from\n";
$header .= "MIME-Version: 1.0\n";
if (empty($files)) {
$header .= "Content-Type: text/plain; charset=\"iso-2022-jp\"\n";
} else {
$header .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\n";
}
$header .= "Content-Transfer-Encoding: 7bit";

//メール送信
if (mail($to, $subject, $body, $header)) {
echo 'メールが送信されました。';
} else {
echo 'メールの送信に失敗しました。';
}

?>

以上、よろしくお願いします

A 回答 (3件)

ANo.2のソースに転送処理を組み込んでみました。

とりあえず添付ファイルなどがあっても問題なく転送出来ています。参考にどうぞ。

<?php
$server = 'POPサーバ名';
$user = 'メールアカウント';
$pass = 'パスワード';

$log = array();
$dat = array();
$sock = fsockopen($server, 110, $errno, $errstr, 20) or die(sprintf('cannot connect %d, %s', $errno, $errstr));
$buf = fgets($sock, 512);
if(substr($buf, 0, 3) != '+OK') die($buf);
$buf = _sendcmd("USER $user");
$buf = _sendcmd("PASS $pass");
$data = _sendcmd("STAT");//STAT -件数とサイズ取得 +OK 8 1234
sscanf($data, '+OK %d %d', $num, $size);
for($i=1; $i<=$num; $i++) {
$line = _sendcmd("RETR $i");
$dat[$i] = '';
while (!preg_match("/^\.\r\n/", $line)) {
$line = fgets($sock,512);
$dat[$i] .= $line;
}
// $data = _sendcmd("DELE $i");
}
$buf = _sendcmd("QUIT");
fclose($sock);
file_put_contents('pop3log.txt', implode(PHP_EOL, $log));

foreach ($dat as $key=>$val) {
$out = md5(microtime()) . '.txt';
file_put_contents($out, $val);
printf('%03d : %s<br>', $key, $out);
_mailsend($val);
}

function _sendcmd($cmd) {
global $sock, $log;
fputs($sock, $cmd."\r\n");
$log[] = 'send : ' . $cmd;
$buf = fgets($sock, 512);
$log[] = 'recv : ' . $buf;
if(substr($buf, 0, 3) == '+OK') {
return $buf;
} else {
die($buf);
}
return false;
}

function _mailsend($arg) {
$mail = explode("\r\n", $arg);
$head = array();
$body = array();
$sw = 0; // 0:ヘッダ、1~:ボディ
foreach($mail as $line) {
if (trim($line) == '') { $sw++; } // 空行があったらヘッダ終了
if ($sw == 0) { // ヘッダチェック
$hf = false; // 残すヘッダは true
if ((substr($line, 0, 1) != " ")&&(substr($line, 0, 1) != "\t")) {
if (strtolower(substr($line, 0, 7)) == "content") { $hf = true; } // content* は残す
if (strtolower(substr($line, 0, 4)) == "from") { // fromはx-org-fromにして残す
$line = 'x-org-' . $line;;
$hf = true;
}
}
}
switch ($sw) {
case 0:
if ($hf) { $head[] = rtrim($line); }
break;
default:
$body[] = rtrim($line);
break;
}
}
$head[] = 'From: 自分のメールアドレス';
return mail('転送先メールアドレス', 'test', implode("\r\n", $body), implode("\r\n", $head)); // subjectに日本語を使うときはmime処理なども自前で
}
    • good
    • 0
この回答へのお礼

shimix様

御丁寧にありがとうございます。
参考にさせて頂きます。

ただ、私の方で、頂いたソースの
'POPサーバ名';
'メールアカウント';
'パスワード';
'自分のメールアドレス';
'転送先メールアドレス'
部分のみを変更し、実行すると、メールは転送されるのですが、
本文にヘッダーの一部が入り、添付ファイルが添付されていない状態となりました(汗

件名 OKです!
本文 ヘッダーの一部+本文+添付ファイルの文字情報
添付ファイル 添付されていない状態

CPIの環境でしょうか(汗

本日より2日ほど出張の為、
帰ってきたら、頂いたソースを参考に、再チャレンジしてみます。

現在、メール本文は、下記のような状態となっております。
ソース表示ではなく、届いたメールを開いた状態です。

********** メール本文ここから **********

Content-Type: multipart/mixed;

From: (自分のメールアドレス)
X-Brightmail-Tracker: AAAAAA==
X-Brightmail-Tracker: AAAAAA==



This is a multi-part message in MIME format.

--------------050804090906090400040804

Content-Type: text/plain; charset=ISO-2022-JP

Content-Transfer-Encoding: 7bit


(本文)



--------------050804090906090400040804

Content-Type: application/x-zip-compressed;

name="test.zip"

Content-Transfer-Encoding: base64

Content-Disposition: attachment;

filename="test.zip"



UEsDBAoAAAAAALQJe0QAAAAAAAAAAAAAAAAIAAAAdGVzdC50eHRQSwECPwAKAAAAAAC0CXtE

AAAAAAAAAAAAAAAACAAkAAAAAAAAACAAAAAAAAAAdGVzdC50eHQKACAAAAAAAAEAGAChtlBZ

DknPAaG2UFkOSc8BobZQWQ5JzwFQSwUGAAAAAAEAAQBaAAAAJgAAAAAA

--------------050804090906090400040804--



.

********** ここまで **********

お礼日時:2014/03/27 07:57

生のメールデータに可能な限り近い状態のテキストってqdmailで扱えませんでしたっけね。

textパート($receiver->text())じゃなくて生メールデータの「テキスト」です。これを間違うと意味がないです。$receiver->body_allとかで採れないのかなぁ・・・。

#PEARのNet_IMAPやNet_POP3も保守されてないので
#お勧めしにくいですしね。


POP3限定で自前で(socketで繋いで)メールデータを取得するなら下記のような手法もあります。レッツphpさんの写メールBBSのソース(pop.php)を改変したものです。

<?php
$server = 'pop3サーバ名';
$user = 'メールアカウント or メールアドレス';
$pass = 'パスワード';

$log = array();
$dat = array();
$sock = fsockopen($server, 110, $errno, $errstr, 20) or die(sprintf('cannot connect %d, %s', $errno, $errstr));
$buf = fgets($sock, 512);
if(substr($buf, 0, 3) != '+OK') die($buf);
$buf = _sendcmd("USER $user");
$buf = _sendcmd("PASS $pass");
$data = _sendcmd("STAT");//STAT -件数とサイズ取得 +OK 8 1234
sscanf($data, '+OK %d %d', $num, $size);
for($i=1; $i<=$num; $i++) {
$line = _sendcmd("RETR $i");
$dat[$i] = '';
while (!preg_match("/^\.\r\n/", $line)) {
$line = fgets($sock,512);
$dat[$i] .= $line;
}
// 削除してよければコメントアウトを外す
// $data = _sendcmd("DELE $i");
}
$buf = _sendcmd("QUIT");
fclose($sock);
file_put_contents('pop3log.txt', implode(PHP_EOL, $log)); // ログをファイルに書き出す

foreach ($dat as $key=>$val) {
$out = md5(microtime()) . '.txt'; // メールデータを書き出すファイル名
file_put_contents($out, $val);
printf('%03d : %s<br>', $i, $out);
}

function _sendcmd($cmd) {
global $sock, $log;
fputs($sock, $cmd."\r\n");
$log[] = 'send : ' . $cmd;
$buf = fgets($sock, 512);
$log[] = 'recv : ' . $buf;
if(substr($buf, 0, 3) == '+OK') {
return $buf;
} else {
die($buf);
}
return false;
}


これで吐き出したメールデータを見れば「どの部分を書き替えて送ればいいか」がわかってくると思います。Content-typeも(それに付随するboundaryも)本文パートも元のメールのまま送る必要があります。mb_convert_encodingすらやってはいけません(なのでmb_send_mailじゃなくてmailを使う)。逆に言えばFromやToやSubjectとか書き替えていいですし(mail関数がセットしますしね)Receivedヘッダはいったん削除してもいいですよね。
    • good
    • 0

メールデータの構造を解析して同じように組み立て直すのは無駄が多いと思います。



#たまに真っ当な構造になっていないメールもありますし(苦笑

gdmailを使っていれば、生のメールデータ(テキストデータ)で取得出来ると思います。メールテキストをヘッダ部(最初の「改行のみ」の行まで)とボディ部に分割すれば如何でしょうか?ヘッダ部の中の「From:」や「To:」を「X-org-From:」や「X-org-To:」に置換して、全部をAdditionalHeader(mail関数の第4引数)に渡せばいいのでは?もちろん適当なヘッダを付加して「転送したメール」であることを主張してもいいです(汗
    • good
    • 0
この回答へのお礼

shimix様

早速の回答、ありがとうございます。
質問の送信用phpを使わず、言われたように、

$from_mail = $receiver->header( array('from','mail') , 'none');
$text = mb_convert_encoding(($receiver->text()),"Shift-JIS","auto");

$to ='(送信先)';
$subject = '(件名)';
$message = $text;
$attach = $receiver->attach();//添付ファイル
$message .= $attach ;
$header = "From: $from_mail";

//メール送信
if (mail($to, $subject, $message, $header)) {
echo 'メールが送信されました。';
} else {
echo 'メールの送信に失敗しました。';
}

としたところ、本文、件名、ヘッダーとも転送されるのですが、
添付ファイルが添付されない状態となります。
(転送先で、添付が存在しない状態です)

私のプログラムの書き方が、どこか違うと思いますので、
よろしければ、正しいソースで教えて頂けると幸いです。

お礼日時:2014/03/26 22:18

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!