使用 Exchange Online 上傳大型附件
Exchange Online 的郵件大小上限為 150 MB。換句話說,只要寄件者與收件者的信箱皆支援,Exchange Online 就能接收與傳送大小在此上限以內的郵件。
從一些新建立的信箱來看,企業帳戶的最大接收郵件大小為 125 MB,而最大寄送大小則為 150 MB。這些數值來自於 ExchangeOnlineEnterprise-8fc1c029-5e32-485e-9810-179fb470144 的信箱方案。不同類型的信箱會有不同的寄送與接收限制,使用者的信箱在過去也可能被設定為較低的限制。若要檢查,請執行下列指令:
Get-ExoMailbox -ResultSize Unlimited -Properties MaxSendSize, MaxReceiveSize | Format-Table DisplayName, MaxReceiveSize, MaxSendSize
處理大型附件
使用 Outlook 用戶端傳送超大郵件相對簡單:建立一封新郵件,附加一些大型檔案,然後直接傳送即可。以程式的方式操作時,概念相同,但在上傳單一附件到 Outlook 郵件時會有 3 MB 的限制。若附件超過此大小,就需要特殊處理。
根據 Microsoft 的說明,處理步驟為:「建立一個上傳工作階段(upload session),並反覆使用 PUT 指令,依序上傳檔案的位元組區段,直到整個檔案上傳完成為止。」
然而,當網路狀況不太穩定時,使用上傳工作階段是一個不錯的選擇,因為它可以將上傳分成多個區塊進行,若其中某個區塊傳輸失敗,也能從中斷的地方繼續上傳。
以區塊方式上傳大型附件
由於附件在編碼時會佔用部分大小,因此實際上單一檔案的可上傳上限會比名義限制小一些。Exchange Online 郵件的最大大小限制是指:包含郵件本文、所有附件,以及編碼所需的額外空間。因此,必須特別注意整封郵件的總大小不可超過 150 MB。
以下是將大型附件以區塊方式上傳的步驟:
1.建立草稿郵件:先建構郵件結構,並執行 New-MgUserMessage Cmdlet。完成後,寄件者信箱中會有一封草稿郵件。
2.建立上傳工作階段:執行 New-MgUserMessageAttachmentUploadSession Cmdlet 建立新的上傳工作階段。回傳的結果會包含一個上傳 URL,其中含有授權用的權杖(token),可用來將附件上傳至目標信箱。該權杖具備時效限制(通常為從上傳會話開始後的兩小時內),在時效內必須完成上傳。若在時間到期前未完成整個附件的傳輸,上傳工作階段會終止,Exchange Online 將捨棄所有已上傳的資料。
3.上傳附件內容:使用一連串的 PUT 請求上傳二進位區塊,每個區塊大小為 320 KB,直到整個檔案完成為止。若符合 320 KB 的倍數,也可以使用最大 4 MB 的區塊進行上傳。
4.傳送郵件:完成上傳後,使用 Send-MgUserMessage Cmdlet 傳送包含附件的草稿郵件。
假設你已經建立好一封包含收件者、寄件者地址、郵件主旨、郵件內容等資訊的郵件結構。為了準備上傳一個大型附件,我們首先建立一個雜湊表(Hash Table),其中包含附件的檔案名稱與大小等資訊。
powershell
複製編輯
$AttachmentFile = "C:\Temp\PowerShellBook.pdf"
[int32]$MaxAttachmentSize = 146800640 # 設定上限為 140 MB(略低於 Exchange 150 MB 的限制)
$FileStream = New-Object System.IO.StreamReader($AttachmentFile)
$FileSize = $FileStream.BaseStream.Length
# 若檔案超過 140 MB,就停止
If ($FileSize -gt $MaxAttachmentSize) { Write-Host ("附件 {0} 太大({1} bytes),最大允許大小為 {2} bytes(140 MB)" -f $AttachmentFile, $FileSize, $MaxAttachmentSize) Break}
# 建立附件的結構資料
$AttachmentDetail = @{}
$AttachmentDetail.Add("attachmentType", "file")
$AttachmentDetail.Add("name",
[System.IO.Path]::GetFileName($AttachmentFile))
$AttachmentDetail.Add("size", $FileSize) $AttachmentParams = @{}
$AttachmentParams.Add("AttachmentItem", $AttachmentDetail)
下一步 是在寄件者信箱中建立一封草稿郵件,並建立一個上傳工作階段來準備上傳附件至 Exchange Online:
powershell
複製編輯
$NewMessage = New-MgUserMessage -UserId $MsgFrom -Body $MsgParams -ToRecipients $EmailRecipient -Subject $MsgSubject$UploadSession = New-MgUserMessageAttachmentUploadSession -UserId $MsgFrom -MessageId $NewMessage.Id -BodyParameter $AttachmentParams
接下來的步驟 是透過 Do/While 迴圈,將檔案切割為 960 KB 的區塊(960 KB 為 320 KB 的倍數,可減少操作次數),逐區塊上傳,直到完整上傳整個檔案:
powershell
複製編輯
[Int32]$uploadChunkSize = 983040 # 每次上傳 960 KB
$FileOffsetStart = 0
$FileBuffer = [byte[]]::new($UploadChunkSize)
do { $FileChunkByteCount = $FileStream.BaseStream.Read($FileBuffer, 0, $FileBuffer.Length) $FileOffsetEnd = $FileStream.BaseStream.Position - 1
If ($FileChunkByteCount -gt 0) { $UploadRangeHeader = "bytes " + $FileOffsetStart + "-" + $FileOffsetEnd + "/" + $FileSize $FileOffsetStart = $fileStream.BaseStream.Position
# 將檔案區塊轉換為二進位內容
$BinaryContent = New-Object System.Net.Http.ByteArrayContent -ArgumentList @($FileBuffer, 0, $FileChunkByteCount) $FileBuffer = [byte[]]::new($uploadChunkSize) $Headers = @{ 'AnchorMailbox' = $MsgFrom 'Content-Range' = $UploadRangeHeader }
# 執行 PUT 請求上傳該區塊
$Result = (Invoke-RestMethod -Method Put -Uri $UploadSession.UploadUrl -UserAgent "UploadAgent" -Headers $Headers -Body $BinaryContent.ReadAsByteArrayAsync().Result -ContentType "application/octet-stream") }} while ($FileChunkByteCount -ne 0)
這段 PowerShell 腳本展示了如何依據 Microsoft Graph API 與 Exchange Online 的限制,安全且穩定地上傳超大附件。
每一次 PUT 操作的標頭(Headers)中,都包含該區塊在整個檔案中的位元組範圍(byte range)資訊。這些區塊必須依序處理。如果上傳過程中發生錯誤,知道目前處理的是哪個區塊,就能從中斷的地方恢復傳輸,非常實用。
Invoke-RestMethod Cmdlet 所使用的 URL 是由 New-MgUserMessageAttachmentUploadSession Cmdlet 回傳的,該URL 指向 https://outlook.office365.com 的端點,並包含使用者帳號、租用戶(tenant)與草稿郵件的相關資訊。
最後一步,是將現在已包含附件的草稿郵件正式寄出:
powershell
複製編輯
Send-MgUserMessage -UserId $MsgFrom -MessageId $NewMessage.Id
這樣整個大型附件的上傳與郵件傳送流程就完成了。
寄送超大型附件:或許不是日常所需的功能
我們的大多數讀者應該都使用穩定可靠的網路,能夠順利上傳大型附件。不過,在某些情況下,網路環境可能不那麼理想,甚至會有中斷的風險,這正是「區塊上傳(chunking)」發揮作用的時候。


Comments are closed, but trackbacks and pingbacks are open.