- ベストアンサー
phpでのメール転送(添付ファイルつき)について
- phpにて、添付付きメールを、件名だけ変更して、添付ファイルごと外部へ転送する方法について解説します。
- 現在、メール受信したものを、mysqlに保存し、添付ファイルはサーバー上に保存しています。もっと簡潔な方法として、サーバー上に添付ファイルを残さずに済み、未受信のメールのみ1画面上で添付メールを転送できる方法が理想です。
- メール受信処理とメール送信処理の具体的なコード例も提供しています。
- みんなの回答 (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処理なども自前で }
その他の回答 (2)
- shimix
- ベストアンサー率54% (865/1590)
生のメールデータに可能な限り近い状態のテキストって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ヘッダはいったん削除してもいいですよね。
- shimix
- ベストアンサー率54% (865/1590)
メールデータの構造を解析して同じように組み立て直すのは無駄が多いと思います。 #たまに真っ当な構造になっていないメールもありますし(苦笑 gdmailを使っていれば、生のメールデータ(テキストデータ)で取得出来ると思います。メールテキストをヘッダ部(最初の「改行のみ」の行まで)とボディ部に分割すれば如何でしょうか?ヘッダ部の中の「From:」や「To:」を「X-org-From:」や「X-org-To:」に置換して、全部をAdditionalHeader(mail関数の第4引数)に渡せばいいのでは?もちろん適当なヘッダを付加して「転送したメール」であることを主張してもいいです(汗
お礼
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 'メールの送信に失敗しました。'; } としたところ、本文、件名、ヘッダーとも転送されるのですが、 添付ファイルが添付されない状態となります。 (転送先で、添付が存在しない状態です) 私のプログラムの書き方が、どこか違うと思いますので、 よろしければ、正しいソースで教えて頂けると幸いです。
お礼
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-- . ********** ここまで **********