簡體   English   中英

Google API 至 Python 發送的電子郵件中的內聯/嵌入式附件也顯示為附件

[英]Inline / embedded attachments in emails sent by Google API through Python are also shown attached

在過去的幾天里,我一直在為這個問題發愁。 為了澄清我的問題,我正在嘗試發送帶有嵌入圖像的電子郵件。 我主要將這些嵌入圖像用於頁腳或社交媒體圖標。 問題是這些嵌入的圖像隨后會顯示在收件箱中,如此處所示 奇怪的是,當打開 email 時,看不到任何附件,但嵌入了圖像,如下所示 雖然每個 email 提供商的問題表現似乎略有不同,但所有大提供商似乎都存在在收件箱中顯示附件的相同問題,但在打開特定的 email 時卻沒有。

我使用 Python 的標准 MIME 庫,以及 Python 的(相對)新的 EmailMessage MIME object。我的過程看起來有點像這樣:

html_text = MIMEText(message_str, 'html')
html_part = MIMEMultipart('related')
html_part.attach(html_text)

for attachment in attachments:
    mime_attachment = MIMEImage(base64.b64decode(attachment.get('data')),
        _subtype=attachment.get('type'))
    mime_attachment.add_header('Content-ID', f'<{attachment.get("name")}>')
    mime_attachment.add_header('Content-Disposition', 'inline',
        filename=f'{attachment.get("name")}')
    mime_attachment.add_header('Content-Transfer-Encoding', 'base64')
    html_part.attach(mime_attachment)

root_message = EmailMessage()
root_message.make_mixed()
root_message.attach(html_part)

這意味着我的 MIME 層次結構如下所示:

  • 多部分/混合
    • 多部分/相關
      • 文本/html
    • 圖片/png

我使用過許多不同的 MIME 類型和層次結構,但我現在使用此網站作為參考。

在這整個 MIME 過程之后,我只是將它轉換為字節,base64 對其進行編碼並通過 GMail API 發送。

Gmail 向我顯示的原始消息看起來不錯,所有類型都是正確的,如上面的 MIME 層次結構所示。 圖片部分顯示為:

--00000000000064aaa005efdc1b1b
Content-Type: image/png; name="9a57c8bb80784228ae77975a659f83c6.png"
Content-Disposition: inline; filename="9a57c8bb80784228ae77975a659f83c6.png"
Content-Transfer-Encoding: base64
Content-ID: <9a57c8bb80784228ae77975a659f83c6>
X-Attachment-Id: cb9a6d0733ed31c7_0.0.2

我嘗試了許多不同的 MIME 層次結構,也嘗試使用 EmailMessage 的 add_attachment 無濟於事。 我有時會使用內聯圖像,收件箱中沒有附件,但是當我打開電子郵件時,整個圖像都在 message/rfc822 類型的附件中,采用 base64 編碼。 在這一點上,我在牆上亂扔東西,看看有什么粘住,但只要有東西朝着正確的方向邁出一步,東西就會變得很奇怪。

使用外部托管圖像對我來說不是一個選項,也不是將整個圖像編碼為 base64 並將其放入 html。

我希望有人能給我提供任何見解。 這以前對我有用,所以我對這一切很困惑。 我提前謝謝你。

編輯:我已經繼續並重構了代碼——我同時嘗試了一些東西但沒有結果。 我嘗試手動創建 MIMEPart 負載,並使用 EmailMessage 的 add_attachment,但無濟於事。 我也嘗試過混合/替代/相對的任何組合,但沒有任何改進。 這是我更新的代碼:

# Creating container for HTML and adding pixel and message (alternative part and images go here)
related_part = MIMEMultipart('related')

# Creating container for html_part and images (HTML and plain go here)
alternative_part = MIMEMultipart('alternative')

# Creating a MIMEText object to hold our HTML
html_text = MIMEText(message_str, 'html')
alternative_part.attach(html_text)

# Adding content to the related part, making the hierarchy like so:
#   * multipart/related
#       * multipart/alternative
#           * html/text
related_part.attach(alternative_part)

# Adding attachments to the container, to look like so:
#   * multipart/related
#       * multipart/alternative
#           * html/text
#       * image / png
for attachment in attachments:
    mime_attachment = MIMEImage(base64.b64decode(attachment.get('data')), _subtype=attachment.get('type'))
    mime_attachment.add_header('Content-ID', f'<{attachment.get("name")}>')
    mime_attachment.add_header('Content-Disposition', 'inline')
                               #filename=f'{attachment.get("name")}.{attachment.get("type")}')
    mime_attachment.add_header('Content-Transfer-Encoding', 'base64')
    related_part.attach(mime_attachment)

# Creating the root EmailMessage
root_message = EmailMessage(EmailPolicy(utf8=True))
root_message.make_mixed()

# Attaching the actual message to the root, to look like this:
#   * multipart/mixed
#       * multipart/related
#           * multipart/alternative
#               * html/text
#           * image / png
root_message.attach(related_part)

root_message['To'] = f"{recipient_name} <{recipient_email}>"
root_message['From'] = f"{self.sender_name} <{self.sender_email}>"
root_message['Subject'] = subject_str
return {
    'raw': base64.urlsafe_b64encode(root_message.as_bytes()).decode()
}

返回的數據通過 Google 的 API 客戶端發送,如下所示:

service.users().messages().send(userId="me", body=mail_data).execute()

我也已將此問題上報給 Google 的跟蹤器: https://issuetracker.google.com/issues/263427102

問題是文件大小。 看起來,大多數郵件提供商對內聯圖像都有最大文件大小。 這些內聯圖像仍將內聯顯示在大多數設備和客戶端上,但它們仍將同時顯示為附件。

Gmail、Gsuite、Office 和其他網絡郵件都有不同的最大文件大小。 當我強制執行最大 15kB 時,這些郵件提供商都沒有抱怨,我的所有文件都很好並且內聯。

當然,由於有數百條 email 消息,我不會手動執行此操作,而是使用 PIL/Pillow 編寫了一個小腳本來減小圖像大小,直到達到特定大小。

img_out = io.BytesIO(image_data)
img = Image.open(img_out)

while getsizeof(img_out) > 15000:
    img_out = io.BytesIO()
    width, height = img.size
    new_width, new_height = int(width * 0.95), int(height*0.95)
    img.thumbnail((new_width, new_height), Image.Resampling.LANCZOS)
    img.save(img_out, 'jpeg')
    size = getsizeof(img_out)

image_data = img_out.getvalue()
with open('downscaled_image.jpeg', 'wb') as writefile:
    writefile.write(image_data)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM