PHP Conference Japan 2024

imap_fetchbody

(PHP 4, PHP 5, PHP 7, PHP 8)

imap_fetchbody擷取郵件主體的特定部分

描述

imap_fetchbody(
    IMAP\Connection $imap,
    int $message_num,
    string $section,
    int $flags = 0
): string|false

擷取指定郵件主體的特定部分。此函式不會解碼主體部分。

參數

imap

一個 IMAP\Connection 實例。

message_num

郵件編號

section

部分編號。它是一個以句點分隔的整數字串,根據 IMAP4 規範索引到主體部分列表。

flags

一個位元遮罩,包含以下一或多個值

  • FT_UID - message_num 是一個 UID
  • FT_PEEK - 如果尚未設定,則不要設定 \Seen 旗標
  • FT_INTERNAL - 回傳字串為內部格式,不會正規化為 CRLF。

回傳值

以文字字串的形式回傳指定郵件主體的特定部分,失敗時回傳 false

變更日誌

版本 描述
8.1.0 imap 參數現在預期一個 IMAP\Connection 實例;先前,預期一個有效的 imap 資源

參見

新增筆記

使用者貢獻筆記 35 筆筆記

74
atamido at gmail dot remove dot com
15 年前
imap-fetchbody() 將會內嵌解碼附加的電子郵件訊息,與電子郵件的其他部分一起,但是,處理附加電子郵件訊息的方式與主要電子郵件訊息不一致。

如果電子郵件訊息僅包含文字主體,且沒有任何 MIME 附件,則 imap-fetchbody() 將針對每個請求的部分編號傳回以下內容

(空白) - 整個訊息
0 - 訊息標頭
1 - 主體文字

如果電子郵件訊息是以 MIME 格式的多部分訊息,且包含純文字和 HTML 格式的訊息文字,並且有一個 file.ext 附件,則 imap-fetchbody() 將針對每個請求的部分編號傳回類似以下內容

(空白) - 整個訊息
0 - 訊息標頭
1 - MULTIPART/ALTERNATIVE
1.1 - TEXT/PLAIN
1.2 - TEXT/HTML
2 - file.ext

現在,如果您將上述電子郵件附加到一個包含純文字和 HTML 格式訊息文字的電子郵件,imap_fetchbody() 將使用此類型的部分編號系統

(空白) - 整個訊息
0 - 訊息標頭
1 - MULTIPART/ALTERNATIVE
1.1 - TEXT/PLAIN
1.2 - TEXT/HTML
2 - MESSAGE/RFC822 (整個附加訊息)
2.0 - 附加訊息標頭
2.1 - TEXT/PLAIN
2.2 - TEXT/HTML
2.3 - file.ext

請注意,file.ext 現在與純文字和 HTML 位於同一層級,並且沒有辦法存取附加訊息中的 MULTIPART/ALTERNATIVE。

以下是先前貼文中部分程式碼的修改版本,它將建構一個容易存取的陣列,其中包含可存取的附加訊息部分,以及在沒有多部分 MIME 時的訊息主體。$structure 變數是 imap_fetchstructure() 函式的輸出。回傳的 $part_array 具有 'part_number' 欄位,其中包含要直接饋送到 imap_fetchbody() 函式的部分編號。

<?php
function create_part_array($structure, $prefix="") {
//print_r($structure);
if (sizeof($structure->parts) > 0) { // 有子部分
foreach ($structure->parts as $count => $part) {
add_part_to_array($part, $prefix.($count+1), $part_array);
}
}else{
// 電子郵件的文字沒有單獨的 MIME 附件
$part_array[] = array('part_number' => $prefix.'1', 'part_object' => $obj);
}
return
$part_array;
}
// create_part_array() 的子函式。僅由 create_part_array() 和自身呼叫。
function add_part_to_array($obj, $partno, & $part_array) {
$part_array[] = array('part_number' => $partno, 'part_object' => $obj);
if (
$obj->type == 2) { // 檢查此部分是否為附加的電子郵件訊息,如 RFC-822 類型
//print_r($obj);
if (sizeof($obj->parts) > 0) { // 檢查電子郵件是否有部分
foreach ($obj->parts as $count => $part) {
// 再次在此處迭代以補償 imap_fetchbody() 處理附件的錯誤方式
if (sizeof($part->parts) > 0) {
foreach (
$part->parts as $count2 => $part2) {
add_part_to_array($part2, $partno.".".($count2+1), $part_array);
}
}else{
// 附加的電子郵件的文字沒有單獨的 MIME 附件
$part_array[] = array('part_number' => $partno.'.'.($count+1), 'part_object' => $obj);
}
}
}else{
// 不確定這是否可能
$part_array[] = array('part_number' => $prefix.'.1', 'part_object' => $obj);
}
}else{
// 如果有更多子部分,則展開它們。
if (sizeof($obj->parts) > 0) {
foreach (
$obj->parts as $count => $p) {
add_part_to_array($p, $partno.".".($count+1), $part_array);
}
}
}
}
?>
72
tom at tomwardrop dot com
16 年前
如果文字已編碼為 quoted-printable(大多數內文都以此編碼),則必須解碼才能正確顯示(不會在字串中出現 '='、'=20' 和其他奇怪的文字區塊)。

若要解碼,您可以使用下列內建的 php 函式...

quoted_printable_decode($string)

希望我剛剛讓一些人不用對其電子郵件內文執行 preg_replace。
15
jab_creations at yahoo dot com
4 年前
第三個參數(section 參數)沒有適當的文件記錄,而且我在研究以釐清這個問題時,看到十幾個開發人員得出絕望的結論。務必了解,各種電子郵件供應商(例如 AOL、Gmail、Microsoft、Yahoo 和用戶端程式,如 Thunderbird 以及...是的,五千個版本的 Outlook)並未遵循某些「標準」。

- 與 JavaScript 和 PHP 的一般運作方式不同,所有索引號碼都從 1 開始,而不是 0。
- 如果沒有第二個 'parts' 陣列(我這裡「不」使用類別),您的第三個/section 參數會是整數。
- 如果 'parts' 陣列包含 'parts' 子陣列,您會有浮點數(例如 1.1 或 2.1 而不是 1 或 2)。如果 'parts' 子陣列中有兩個部分,則會有類似 1.1 和 1.2 或 2.1 和 2.2 的數字 - 請記住:這些會因供應商而異,而且沒有「標準」,因為這是 PHP 特有的問題!
- 沒有、一些或所有 'parts' 陣列可能是單數或包含子 'parts' 子陣列,這是完全動態的,甚至可能在同一供應商中不一致!

以下假設您有一個 $mail_connection,並且知道您正在使用的 $email_number 編號

<?php
$i
= 0;//第一層部分參考。
$j = 0;//第二層部分參考。
$mail_message_structure = json_decode(json_encode(imap_fetchstructure($mail_connection, $email_number)), true);//從類別樣式轉換。

while ($i < count($mail_message_structure['parts']))
{
if (isset(
$mail_message_structure['parts'][$i]['parts']))
{
//多個,包含第二個 'parts' 陣列。
while ($j < count($mail_message_structure['parts'][$i]['parts']))
{
//使用一律小寫來移除「Png/PNG/png」的主觀性。
$mail_message_structure['parts'][$i]['parts'][$j]['subtype'] = strtolower($mail_message_structure['parts'][$i]['parts'][$j]['subtype']);
$mail_message_structure['parts'][$i]['parts'][$j]['id_imap_fetchbody'] = ($i + 1).'.'.($j + 1);
echo
'<p>'.$i.': multi, '.$j.' '.$mail_message_structure['parts'][$i]['parts'][$j]['subtype'].': '.($i + 1).'.'.($j + 1).'</p>';
$j++;
}
}
else
{
//單一,第一層。
//使用一律小寫來移除「Png/PNG/png」的主觀性。
$mail_message_structure['parts'][$i]['subtype'] = strtolower($mail_message_structure['parts'][$i]['subtype']);
$mail_message_structure['parts'][$i]['id_imap_fetchbody'] = ($i + 1);
echo
'<p>'.$i.': single: '.$mail_message_structure['parts'][$i]['subtype'].': '.($i + 1).'</p>';
}
$i++;
}
?>

現在我們實際上可以了解「如何」存取電子郵件內文的特定「部分」,因此只要簡單地迭代結構陣列即可

<?php
foreach ($mail_message_structure['parts'] as $k4 => $v4)
{
if (isset(
$v4['parts']))
{
foreach (
$v4['parts'] as $k5 => $v5) {mail_imap_body($mail_connection, $email_number, $v5);}//echo '<div>MULTI: '.$v5['id_imap_fetchbody'].'; <pre>'.htmlspecialchars(print_r($v4['parts'],1)).'</pre></div>';
}
else {
mail_imap_body($mail_connection, $email_number, $v4);}//echo '<div>SINGLE: '.$v4['id_imap_fetchbody'].'<pre>'.htmlspecialchars(print_r($v4,1)).'</pre></div>';
}
?>
10
red dot ender at yahoo dot com
11 年前
我從 Gmail 提取文字時,德語變音符號 (umlauts) 出現了一些問題。我花了一個小時試圖找到解決方案。

希望這對有需要的人有幫助 :)

<?php
$text
= trim( utf8_encode( quoted_printable_decode(
imap_fetchbody( $this->inbox, $emailNo, $section ) ) ) );

$section 先前已定義:
$section = empty( $attachments ) ? 1 : 1.1;
?>
8
gesti at gmx dot com
12 年前
如何在「options」參數中提供多個選項
我花了一些時間才意識到它有多簡單,所以以防萬一其他人也會在這方面感到困惑
<?php
imap_fetchbody
($imap_stream, $msg_number, $section, FT_UID | FT_PEEK);
?>
4
mike at lathyrus dot net
9 年前
我花了幾個小時虔誠地認為

imap_fetchbody($mbox,$email_number,1.2)

會提取 HTML 內文,而且在許多情況下這樣做並不起作用。結果發現,簡單的訊息可以具有簡單的 [parts] 結構,因此這就成真了

imap_fetchbody($mbox,$email_number,1) - 純文字
imap_fetchbody($inbox,$email_number,2) - HTML

在使用後者之前檢查是否為空字串。
1
rfinnie at kefta dot com
23 年前
關於 message/rfc822 部分,似乎 PHP 使用的 IMAP c-client 並未正確遵循 IMAP RFC (#2060)。RFC 規定,要取得 message/rfc822 部分的標頭,您應該請求部分 "2.HEADER"(假設 2 是您的部分編號),而該部分的完整文字將為 "2.TEXT"。相反,"2.0" 將取得標頭,而僅 "2" 將取得文字。
2
caevan at amkd dot com dot au
12 年前
我嘗試使用下面的 function add_part_to_array,並注意到拋出了一些錯誤。如果結構中沒有 'parts',則 if (sizeof($obj->parts) > 0) 將拋出錯誤。此外,$prefix 在這裡沒有定義,這是我更新的程式碼。我將原始程式碼行註解掉了。我已經測試過從 Gmail 帳戶讀取電子郵件,目前為止一切順利。

<?php

// create_part_array() 的子 function。僅由 create_part_array() 和自身呼叫。
function add_part_to_array($obj, $partno, & $part_array) {
$part_array[] = array('part_number' => $partno, 'part_object' => $obj);

if (
$obj->type == 2) { // 檢查部分是否為附加的電子郵件訊息,如 RFC-822 類型
// if (sizeof($obj->parts) > 0) { // 檢查電子郵件是否有部分
if(array_key_exists('parts',$obj){
foreach (
$obj->parts as $count => $part) {
// 在這裡再次迭代以補償 imap_fetchbody() 處理附件的損壞方式
if (sizeof($part->parts) > 0) {
foreach (
$part->parts as $count2 => $part2) {
add_part_to_array($part2, $partno.".".($count2+1), $part_array);
}
}else{
// 附加的電子郵件沒有用於文字的獨立 mime 附件
$part_array[] = array('part_number' => $partno.'.'.($count+1), 'part_object' => $obj);
}
}
}else{
// 不確定這是否可能
// $part_array[] = array('part_number' => $prefix.'.1', 'part_object' => $obj);
$part_array[] = array('part_number' => $partno.'.1', 'part_object' => $obj);
}
}else{
// 如果有更多子部分,則將它們展開。
// if (sizeof($obj->parts) > 0) {
if(array_key_exists('parts',$obj)){
foreach (
$obj->parts as $count => $p) {
add_part_to_array($p, $partno.".".($count+1), $part_array);
}
}
}
}
?>
4
ulrich at kaldamar dot de
21 年前
函數 imap_fetchbody() 似乎無法取得 message/rfc822 部分的子部分。我曾遇到取得以該部分轉寄的附件的問題,因為 imap_fetchstructure() 提供的物件會假設該部分由字串 "2.1.2.1.2" 表示。

所以我寫了這組函數,它會剖析原始訊息內文,並建立一個陣列,其結構與 imap_fetchstructure() 提供的結構對應。函數 mail_fetchpart()(請見下方)將會在陣列上運作,並傳回我無法使用 imap_fetchbody() 取得的那些部分。

此函數的用法範例:mail_fetchpart($mbox, 2, "2.1.2.1.2");

注意:如果訊息不包含多個部分,則可以使用部分字串 "1" 存取訊息的內文。
我還有更多用於剖析和解碼訊息的函數,請寄電子郵件給我。

// 根據 $part 中的字串取得訊息某部分的內文
// $part 中的字串
function mail_fetchpart($mbox, $msgNo, $part) {
$parts = mail_fetchparts($mbox, $msgNo);

$partNos = explode(".", $part);

$currentPart = $parts;
while(list ($key, $val) = each($partNos)) {
$currentPart = $currentPart[$val];
}

if ($currentPart != "") return $currentPart;
else return false;
}

// 如果訊息是以
// multipart mime 訊息的形式在內文中給出,則將其分割並傳回各部分,
// 如果找不到任何部分,則傳回 false
function mail_mimesplit($header, $body) {
$parts = array();

$PN_EREG_BOUNDARY = "Content-Type:(.*)boundary=\"([^\"]+)\"";

if (eregi ($PN_EREG_BOUNDARY, $header, $regs)) {
$boundary = $regs[2];

$delimiterReg = "([^\r\n]*)$boundary([^\r\n]*)";
if (eregi ($delimiterReg, $body, $results)) {
$delimiter = $results[0];
$parts = explode($delimiter, $body);
$parts = array_slice ($parts, 1, -1);
}

return $parts;
} else {
return false;
}


}

// 傳回包含給定部分所有子部分的陣列
// 如果找不到子部分,則傳回目前部分的內文
// 如果找不到子部分,則傳回目前部分的內文
// 目前部分的內文
function mail_mimesub($part) {
$i = 1;
$headDelimiter = "\r\n\r\n";
$delLength = strlen($headDelimiter);

// 取得目前部分的標頭和內文
$endOfHead = strpos( $part, $headDelimiter);
$head = substr($part, 0, $endOfHead);
$body = substr($part, $endOfHead + $delLength, strlen($part));

// 根據 rfc822 檢查是否為訊息
if (stristr($head, "Content-Type: message/rfc822")) {
$part = substr($part, $endOfHead + $delLength, strlen($part));
$returnParts[1] = mail_mimesub($part);
return $returnParts;
// 如果不是訊息,則取得子部分並遞迴呼叫函式
} elseif ($subParts = mail_mimesplit($head, $body)) {
// 取得更多子部分
while (list ($key, $val) = each($subParts)) {
$returnParts[$i] = mail_mimesub($val);
$i++;
}
return $returnParts;
} else {
return $body;
}
}

// 取得一個包含電子郵件所有部分的內容的陣列
// 陣列的結構對應於
// imap_fetchstructure 可用的結構
function mail_fetchparts($mbox, $msgNo) {
$parts = array();
$header = imap_fetchheader($mbox,$msgNo);
$body = imap_body($mbox,$msgNo, FT_INTERNAL);

$i = 1;

if ($newParts = mail_mimesplit($header, $body)) {
while (list ($key, $val) = each($newParts)) {
$parts[$i] = mail_mimesub($val);
$i++;
}
} else {
$parts[$i] = $body;
}
return $parts;

}
1
web at i-ps dot net
17 年前
我在使用 imap_fetchbody 傳回的內容時遇到問題 - 無論是函式本身還是郵件伺服器,都會在傳回的文字內容中插入 "=\r\n"。這可能取決於內容類型(即純文字/csv,而不是像 Word 文件之類的東西),但您可能需要執行類似以下的操作

$body = preg_replace("/=(\r?)\n/", '', imap_fetchbody($mailbox, $message, $part));
1
jbr at ya-right dot com
17 年前
Musawir Ali 的評論並不完全正確,ifdisposition= 1 永遠不會 100% 告訴您是否有附件。您必須查看 (ifdparameters, ifparameters),如果 (1) 其中一個大於 (0),那麼您需要查看 (parameters) 內部,查看每個 ($obj->parameters) 並檢查 (attribute) 是否有 (NAME, FILENAME),在進行測試之前,也請務必將它們設定為大寫或小寫。這是唯一知道是否有附件的方法。內嵌附件的 $obj->ifid 將等於 1,$obj->id 將包含 (cid)。如果 $obj->ifid 等於 0,如果目前的參數 (attribute) 有 (NAME, FILENAME),那麼它也是一個附件(檔案類型)。

<?php
$name
= '';

if (
$parent->ifdparameters && sizeof ( $parent->dparameters ) > 0 )
{
foreach (
$parent->dparameters as $child )
{
if (
strtolower ( $child->attribute ) == 'name' || strtolower ( $child->attribute ) == 'filename' )
{
$name = strtolower ( $child->value );
}
}
}

if ( empty (
$name ) )
{
if (
$parent->ifparameters && sizeof ( $parent->parameters ) > 0 )
{
foreach (
$parent->parameters as $child )
{
if (
strtolower ( $child->attribute ) == 'name' || strtolower ( $child->attribute ) == 'filename' )
{
$name = strtolower ( $child->value );
}
}
}
}
?>

如果 $obj->parts 有設定,則 $parent 是從 imap_fetchstructure() 衍生而來的子物件,否則就是 $parent!
2
jsimlo yahoo com
20 年前
這可能是取得所有部分編號的方法....即使訊息包含另一個附加的訊息,而該訊息又包含另一個附加的訊息...

<?
$parttypes = array ("text", "multipart", "message", "application", "audio", "image", "video", "other");
function buildparts ($struct, $pno = "") {
global $parttypes;
switch ($struct->type)
case 1
$r = array (); $i = 1;
foreach ($struct->parts as $part)
$r[] = buildparts ($part, $pno.".".$i++);

return implode (", ", $r);
case 2
return "{".buildparts ($struct->parts[0], $pno)."}";
default
return '<a href="?p='.substr ($pno, 1).'">'.$parttypes[$struct->type]."/".strtolower ($struct->subtype)."</a>";
endswitch;
}

$struct = imap_fetchstructure ($pop3mbox, $msguid, FT_UID);
echo buildparts ($struct);
?>

它會印出類似這樣的東西

<a href="?p=1">text/plain</a>, {<a href="?p=2.1">text/plain</a>, <a href="?p=2.2">text/html</a>}
1
atamido at gmail dot remove dot com
15 年前
如果您下載標示為 "winmail.dat" 或 "win.dat",或 mime 類型為 "APPLICATION/MS-TNEF" 的附件,這是一個 Microsoft 傳輸中性封裝格式檔案。這是一種用於將多個檔案編碼在單一檔案中的專有方法。據我所知,只有 Outlook 會以預設設定(以 RTF 格式傳送電子郵件)傳送它。

自 PHP 5.2 以來,沒有內建方法可以將這些附件分離。

有一些可以從 PHP 呼叫的外部命令列工具。或者,也可以完全在 PHP 中解碼這些檔案。目前所有的程式庫似乎都是基於 Graham Norbury 為 Squirrel Mail 撰寫的插件。我看到的只有在 IlohaMail、Telean、Horde-Imp 和 NaSMail 中。我只知道 NaSMail 也可以解碼 RTF 訊息。

若要使用 NaSMail 程式碼,請下載「TNEF 附件解碼器」插件並將其解壓縮至
plugins/attachment_tnef/

然後使用這段程式碼
<?php
include_once('plugins/attachment_tnef/constants.php');
include_once(
'plugins/attachment_tnef/functions.php');
include_once(
'plugins/attachment_tnef/class/tnef.php');

// $tnef 是一個僅包含 winmail.dat 內容的二進位變數
$attachment = &new TnefAttachment($tnef_debug);
$result = $attachment->decodeTnef($tnef);
$tnef_files = &$attachment->getFilesNested();
print_r($tnef_files); // 查看傳回陣列的格式
?>
1
php at NOSPAM dot sibyla dot cz
20 年前
// $uid - 訊息編號

function read_all_parts($uid){
global $mime,$ret_info,$enc;
$mime = array("text","multipart","message","application","audio",
"image","video","other","unknow");
$enc = array("7BIT","8BIT","BINARY","BASE64",
"QUOTED-PRINTABLE","OTHER");


$struct = imap_fetchstructure( $this -> Link, $uid );

$ret_info = array();

function scan($struct,$subkey){
global $mime,$enc,$ret_info;

foreach($struct as $key => $value){


if($subkey!=0){
$pid = $subkey.".".($key+1); }
else { $pid = ($key+1); }

$ret_info[]['pid'] = $pid;
$ret_info[key($ret_info)]['type'] = $mime["$value->type"];
$ret_info[key($ret_info)]['encoding'] = $enc["$value->encoding"];

next($ret_info);

if(($value->parts)!= null) {scan($value->parts,$pid); }
}

}

scan($struct->parts,0);

return $ret_info;

}
1
noose (at) nospam (dot) tweak (dot) pl
20 年前
抱歉我的英文不好....

為了讀取附件

<?
foreach ($_GET as $k => $v)
{
$$k = $v;
}
$login = 'mylogin';
$password = 'mypassword';
$host = '{myhost:110/pop3}';

$mbox = imap_open("$host", "$login", "$password");
$struckture = imap_fetchstructure($mbox, $id);
$message = imap_fetchbody($mbox,$id,$part);
$name = $struckture->parts[$part]->dparameters[0]->value;
$type = $struckture->parts[$part]->typee;
############## 類型
if ($type == 0)
{
$type = "text/";
}
elseif ($type == 1)
{
$type = "multipart/";
}
elseif ($type == 2)
{
$type = "message/";
}
elseif ($type == 3)
{
$type = "application/";
}
elseif ($type == 4)
{
$type = "audio/";
}
elseif ($type == 5)
{
$type = "image/";
}
elseif ($type == 6)
{
$type = "video";
}
elseif($type == 7)
{
$type = "other/";
}
$type .= $struckture->parts[$part]->subtypee;
######## 類型結束

header("Content-typee: ".$type);
header("Content-Disposition: attachment; filename=".$name);

######## 編碼
$coding = $struckture->parts[$part]->encoding;
if ($coding == 0)
{
$message = imap_7bit($message);
}
elseif ($coding == 1)
{
$wiadomsoc = imap_8bit($message);
}
elseif ($coding == 2)
{
$message = imap_binary($message);
}
elseif ($coding == 3)
{
$message = imap_base64($message);
}
elseif ($coding == 4)
{
$message = quoted_printable($message);
}
elseif ($coding == 5)
{
$message = $message;
}
echo $message;
########## 編碼結束
imap_close($mbox);
?>
0
tabaccoandcoffee at gmail dot com
10 年前
抱歉我的英文不好。
與其使用 quoted_printable_decode,您可以使用函式 imap_qprint ($body)
2
anonymous at coward dot village
17 年前
處理附件的一個非常簡單的方法是直接使用 munpack,建立一個名為 attachments 的子目錄,將其權限設為 777,然後在 MIME 編碼的郵件內容上使用以下程式碼(需要安裝 mpack):

<?php
//email MIME body in $input
file_put_contents("attachments/body.eml",$input);
$command = "munpack -C attachments -fq body.eml";
exec($command,$output);
if(
$output[0]!='Did not find anything to unpack from body.eml') {
foreach (
$output as $attach) {
$pieces = explode(" ", $attach);
$part = $pieces[0];
echo
"<a href=\"attachments/$part\">$part</a><br>";
}
}
?>
1
atamido at gmail dot remove dot com
15 年前
先前的貼文包含一個複製/貼上錯誤和一些額外的複雜性。第一個函式應該看起來像這樣

<?php
function create_part_array($struct) {
if (
sizeof($struct->parts) > 0) { // 有一些子部分
foreach ($struct->parts as $count => $part) {
add_part_to_array($part, ($count+1), $part_array);
}
}else{
// 電子郵件沒有單獨的 MIME 附件來存放文字
$part_array[] = array('part_number' => '1', 'part_object' => $struct);
}
return
$part_array;
}
?>
1
anonymous lazy person
16 年前
針對下方關於使用 munpack 提取附件的評論進行擴充,以下是一個懶人函式,可以從 $mailbox 中的 $msg_number 郵件中提取附件,並將它們寫入 $dir。如果沒有附件,則返回檔案名稱陣列或 false。

function writeAttachmentsToDisk($mailbox, $msg_number, $dir){

if (!file_exists($dir)){
mkdir($dir);
}
$filename = "tmp.eml";
$email_file = $dir."/".$filename;
// 將郵件內容寫入磁碟
imap_savebody ($mailbox, $email_file, $msg_number);
$command = "munpack -C $dir -fq $email_file";
// 呼叫 munpack,這會
// 將所有附件寫入 $dir
exec($command,$output);

// if($output[0]!='Did not find anything to unpack from $filename') {
$found_file = false;
foreach ($output as $attach) {
$pieces = explode(" ", $attach);
$part = $pieces[0];
if (file_exists($dir.$part)){
$found_file = true;
$files[] = $part;
}
}
if (!$found_file){
//echo ("\nMail.php : no files found - cleaning up. ");
// 沒有找到任何輸出檔案 - 刪除目錄和電子郵件檔案
unlink($email_file);
rmdir($dir);
return false;
}
else {
// 找到一些檔案 - 只需刪除電子郵件檔案
unlink($email_file);
return $files;
}
}
1
bryn
16 年前
ripmime 是 rfc822 郵件的另一個替代方案,而不是 munpack http://www.pldaniels.com/ripmime/

它允許您傳遞 rfc822 附件(通常是 something.eml),並以遞迴方式寫出附件(以及文字和 html 檔案)
2
Sito
20 年前
更好,一個修正上的修正... ;)

function read_all_parts($uid){
global $mime,$ret_info,$enc;
$mime = array("text","multipart","message","application","audio",
"image","video","other","unknow");
$enc = array("7BIT","8BIT","BINARY","BASE64",
"QUOTED-PRINTABLE","OTHER");


$struct = imap_fetchstructure( $this -> Link, $uid );

$ret_info = array();

function scan($struct,$subkey){
global $mime,$enc,$ret_info;

foreach($struct as $key => $value){


if($subkey!=0){
$pid = $subkey.".".($key+1); }
else { $pid = ($key+1); }

$ret_info[]['pid'] = $pid;
$ret_info[key($ret_info)]['type'] = $mime["$value->type"];
$ret_info[key($ret_info)]['encoding'] = $enc["$value->encoding"];

next($ret_info);

if(($value->parts)!= null) {scan($value->parts,$pid); }
}
}

if(!is_null($struct->parts))
{
scan($struct->parts,0);
}
else
{
print_r($struct);
echo("<hr>");
$ret_info[]['pid']=1;
$ret_info[key($ret_info)]['type']=$mime["$struct->type"];
$ret_info[key($ret_info)]['encoding']=$enc["$struct->encoding"];
}

return $ret_info;

}
2
bubblocity at yahoo dot com
22 年前
如果您正嘗試擷取郵件內容,但不確定要擷取什麼,
這是一個函式,它會以單一字串形式傳回所有郵件內容,每個部分以 '|' 字元分隔。
接著是一個函式,它將擷取該部分的結構。

然後,您可以使用 explode() 解析回傳字串,並在每個部分呼叫 imap_fetchbody()。

這段程式碼的部分內容是從以下網站竊取的
http://www.bitsense.net/PHPNotes/IMAP/imap_fetchstructure.asp

<pre>
# 函式取得所有子部分,但不取得部分:''
function GetParts($this_part, $part_no) {

// 如果類型為 message(2)=msg envelope,
// 不確定這個假設:if 語句
// 在這方面與 RFC822 仔細核對。

if($this_part->type==2){
// 且 envelope 只有 1 個子部分
// 且該子部分是多部分的
// 否則會產生過多的 '.1' 和
// 將錯誤的 part_no 傳送到 imap_fetchbody
if($this_part->parts[0]->type==1){
$this_part=$this_part->parts[0];
}
}

if (count($this_part->parts)>0) {
for ($i = 0; $i < count($this_part->parts); $i++) {
if ($part_no != "") {
$newpartno = $part_no . '.' . ($i +1);
}
else $newpartno = $i+1;

$partstringary[$i] =
GetParts($this_part->parts[$i], $newpartno);
}//for
$partstring = implode('|', $partstringary);

}//if
$partstring = concat_ws('|', $part_no , $partstring);
//echo $partstring ;
return $partstring;
}

#########################################
# Companion 函式前往 GetParts();
# 給定 partno - 傳回結構
#########################################
function GetSubPartStructure($mbox, $msgno, $partno){

$msg_struct = imap_fetchstructure($mbox, $msgno);
$partsary = explode ('.', $partno);
$subpartstruct = $msg_struct;

for ($i=0; $i< count($partsary); $i++){
// 不確定這個,如果假設
// 您應該在這方面與 RFC822 仔細核對。
if($subpartstruct->type==2){
if($subpartstruct->parts[0]->type==1){
$subpartstruct=$subpartstruct->parts[0];
}
}
$subpartstruct = $subpartstruct->parts[$partsary[$i]-1];
}
return $subpartstruct;
}

function decodemsg($msgstring, $encoding){
// 編寫您自己的函式來解碼,
// 或已經有許多 PHP 範例。
return $decodemsg;
}

# 使用方式
$msg_struct = imap_fetchstructure($mbox, $msgno);
$msgparts= GetParts($msg_struct, $part_no);
$partsary = explode($msgparts, '|');
for($i=0; $i<count($parsary);$i++){
$substruct = GetSubPartStructure($mbox, $msgno, $partsary[$i]);
if($substruct->type==''){
// 則這是 TEXT 類型
$msg = imap_fetchbody($mbox, $msgno, $msgpartsary[$i]);
// 執行解碼
$msg = decodemsg($msg, $struct->encoding);
echo $msg; // 或用它做任何您想做的事。
}
else{ // 不是 TEXT
// 做任何您想做的事
// 例如:寫入附件...等
}
}

</pre>
2
pmzandbergen at yahoo dot com
23 年前
上面的函式不錯。然而,有些網路郵件服務(通常是純文字)像您一樣,不會將附件使用「ATTACHMENT」結構類型,而是使用「INLINE」(純文字也這樣稱呼)。只要取代
if (strtoupper ($structure->disposition) == "ATTACHMENT"){


if (strtoupper ($structure->disposition) == "ATTACHMENT" || strtoupper ($structure->disposition) == "INLINE" && strtoupper ($structure->subtype) != "PLAIN") {

但是請記住,當您傳送包含純文字和附件的郵件時,純文字也是附件
1
guru at php dot net
20 年前
在與 imap 擴充功能經歷多次交戰後,我決定自行使用 sockets 編寫實作。以下是我所完成的,希望它對其他人也有用。我知道這其中有些部分可以調整,但這部分就留給你們來處理。隨您使用/濫用/損毀,沒有任何許可(授權)。

(注意:我不會在這裡放置原始碼,因為它超過 1900 行 ~48KB)

http://www.nutextonline.com/cimap.phps

如果夠多人覺得有用,我會繼續改進它,並最終將它提交(或讓人提交)到 pear。

另一個值得注意的是,您可以在 mbox 格式的信箱上使用 imap 擴充功能。將此類別與 imap 擴充功能結合使用,如果處理正確,肯定會產生一個很棒的組合。
0
fortega dot no spam plz at uamericas dot net
16 年前
若要擷取「子部分」的內容,請執行下列動作
<?php
$partno
= "2.1" // 第二部分的第一個部分

print_r(imap_fetchbody($mbox, $msgno, $partno));
// TODO: 將 print_r 換成適當的函式
?>

請記住...您可以使用下列方式擷取結構
<?php
imap_fetchstructure
($mbox, $msgno);
?>
然後迭代部分陣列,擷取內容。
0
ted at qtis dot co dot nz
17 年前
以下是擴充 Makusnospam 的小常式的簡單方法,可將整個訊息扁平化為陣列,這對於快速找到內容和附件,只需瀏覽陣列元素非常有用。

function create_part_array($structure, $prefix="") {
$part_array = array();

if (sizeof($structure->parts) > 0) {
foreach ($structure->parts as $count => $part) {
add_part_to_array($part, $prefix.($count+1), $part_array);
}
}

return $part_array;
}

function add_part_to_array($obj, $partno, & $part_array) {

if ($obj->type == TYPEMESSAGE) {
parse_message($obj->parts[0], $partno.".");
}
else {
if (sizeof($obj->parts) > 0) {
foreach ($obj->parts as $count => $p) {
add_part_to_array($p, $partno.".".($count+1), $part_array);
}
}
}

$part_array[] = array('part_number' => $partno, 'part_object' => $obj);
}
0
phpnetlover at yoz dot us
17 年前
大家好

我一直在檢視 RFC,而要顯示的內容答案與 Musawir Ali 在 2 個區域不同

1- 您不能仰賴 disposition 是否存在,並非所有郵件軟體都依照標準撰寫郵件,如果您快速查看 RFC,您會發現有人可能會傳送郵件給您,其中您的解決方案將會失敗,即使郵件是「符合標準」的。

2- 當你遇到 Alternative-multipart 類型時,假設你會找到一個 text-plain 和一個 text-html,你不應該先找 HTML 再找 TEXT,最後提到的子類型最忠實於原始的組成。你應該檢查你是否支援最後一個子類型,如果不支持,你只需退回一步,查看前一個子類型,如果你的客戶端支援,就採用它,以此類推。這就是 Alternative 的運作方式。HTML 呈現效果最佳並不代表我們應該選擇它,我們尋找的是最接近原始呈現的,而不是任何特定的呈現方式。
1
bubblocity at yahoo dot com
21 年前
這是對 2002 年 1 月 14 日 02:58 提交的程式碼的一個遲來的增補。
這個函數是在 GetParts 函數內被調用的。

function concat_ws($separator, $str1, $str2){
if(strlen($str1) && strlen($str2)){
return $str1 . $separator . $str2;
}
else if (strlen($str1)){
return $str1;
}
else if (strlen($str2)){
return $str2;
}
else return '';

}
0
Musawir Ali
18 年前
對於那些試圖建立「彈性」電子郵件閱讀器的人,我建議你們採取以下步驟。

首先,不要逐一瀏覽電子郵件的每個部分並進行解碼,我建議你按照特定的順序進行。

1) 首先瀏覽所有部分,並搜尋子類型 (subtype) 為 'HTML' 的部分。如果找到,則使用它作為你的郵件主體,否則跳到步驟 2。
2) 如果找不到 HTML 元件,則搜尋所有子類型為 'PLAIN' 的部分。如果找到,則使用它作為你的郵件主體,否則顯示錯誤訊息(這不應該發生)。
3) 此時,你應該已經有了要顯示的電子郵件主體。接下來要做的就是找到所有附件。你可以瀏覽所有部分,搜尋 ifdisposition==1 的部分(可能有許多個)。

這是我開發電子郵件閱讀器程式的方法,它運作良好。我最初使用許多網頁推薦的方法(例如,像 1.2.1、1、2 等方式瀏覽部分樹),但問題是郵件主體從不在某個固定的部分!有時在 1,有時在 1.1.2,有時在 2,有時在完全意想不到的地方!所以我的方法是「搜尋」我感興趣的部分。希望這有幫助。我也成功解決了包含嵌入式圖片的電子郵件的問題。我可能會很快寫一篇關於這個的教學。
1
markusNOSPAM at broede dot NO_SPAM dot de
22 年前
也許你更喜歡一種簡短且遞迴的方式來解析訊息
並建立部分編號
-------------------------------------------------------------

function parse_message($obj, $prefix="") {
/* 在此處你可以處理訊息主要「部分」的數據,例如:*/
do_anything_with_message_struct($obj);

if (sizeof($obj->parts) > 0)
foreach ($obj->parts as $count=>$p)
parse_part($p, $prefix.($count+1));
}

function parse_part($obj, $partno) {
/* 在此處你可以處理訊息部分的編號和數據,例如:*/
do_anything_with_part_struct($obj,$partno);

if ($obj->type == TYPEMESSAGE)
parse_message($obj->parts[0], $partno.".");
else
if (sizeof($obj->parts) > 0)
foreach ($obj->parts as $count=>$p)
parse_part($p, $partno.".".($count+1));
}

/* 假設你已經開啟一個信箱串流 $mbox
並且你想解析第一個訊息:*/

$msgno = 1;
parse_message(imap_fetchstructure($mbox,$msgno));
1
sarachaga at yahoo dot com
22 年前
對於那些嘗試正確提取 message/rfc822 部分的人,這裡有一個提示

正如你可能注意到的,如果你遞迴遍歷 imap_fetchstructure 返回的結構物件,當你到達 message/rfc822 時,你會發現訊息本身也算作一個部分,因此該訊息中的附件應該是 2.1.2 (其中 .1. 是整個 rfc822 訊息),但是如果你在 imap_fetchbody 中使用該部分編號,你將一無所獲。

我所做的是:我的遞迴函數檢查特定部分的 part/subtype 是否為 message/rfc822,只有在這種情況下,我才不會將 .1 連接到部分編號,因為據我所知,這僅發生在這種訊息類型中。對於所有其他部分(非 rfc822),它會連接點-部分編號。
1
ac at artcenter dot ac
22 年前
假設你的電子郵件具有以下結構
1 multipart
plain
html
2 x-vcard
而且...你似乎無法找出如何取得 multipart 訊息中的 plain 或 HTML 部分?你是否一直在費盡心思尋找 PHP MIME 解析器?好吧,這是一個簡單的解決方案,應該在這個手冊中記錄。從上面的範例來看,如果你想取得「multipart」訊息的 plain 部分,請執行以下操作
$text=imap_fetchbody($mbox,$msg_num,"1.1");
你要做的就是,不要使用部分編號 1,而是使用 1.1,或者要取得 HTML 部分,則使用 1.2

簡單!
0
se at designlinks dot net
19 年前
如果你堅持使用 imap_fetchbody() 來檢索不包含 'parts' 的郵件主體 [通常你會使用 imap_body() ],請注意標頭文字位於部分 '0' 中,而主體文字位於部分 '1' 中。
因此,imap_fetchbody($mbox,$msg,'0') 將返回標頭,而 imap_fetchbody($mbox,$msg,'1') 將返回主體文字。
0
Adam
20 年前
我花了一段時間才弄清楚如何將部分 ID(編號)分配給訊息的不同部分。在收到一些具有半複雜結構的 AOL 電子郵件後,我終於能夠將其分解。

0 multipart/mixed
1 multipart/alternative
1.1 text/plain
1.2 text/html
2 message/rfc822
2 multipart/mixed
2.1 multipart/alternative
2.1.1 text/plain
2.1.2 text/html
2.2 message/rfc822
2.2 multipart/alternative
2.2.1 text/plain
2.2.2 text/html

希望這可以幫助其他人取得訊息的不同主體部分。
0
asfd at aasdfa dot com
21 年前
請記錄此貼文並為我們節省一些時間! :)
ac at artcenter dot ac
2002 年 2 月 17 日 04:24
假設你的電子郵件具有以下結構
1 multipart
plain
html
2 x-vcard
而且...你似乎無法找出如何取得 multipart 訊息中的 plain 或 HTML 部分?你是否一直在費盡心思尋找 PHP MIME 解析器?好吧,這是一個簡單的解決方案,應該在這個手冊中記錄。從上面的範例來看,如果你想取得「multipart」訊息的 plain 部分,請執行以下操作
$text=imap_fetchbody($mbox,$msg_num,"1.1");
你要做的就是,不要使用部分編號 1,而是使用 1.1,或者要取得 HTML 部分,則使用 1.2

簡單!
To Top