出于安全原因,如何阻止Gmail删除内联图片?

时间:2018-04-27 21:06:00

标签: python-3.x gmail-api

我创建了一个电子邮件应用,用于发送文件夹中的所有.png文件,如下所示:

import httplib2
import os

from apiclient import discovery
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
import base64
import glob
import uuid
import html
import json

try:
    import argparse
    flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
    flags = None

# If modifying these scopes, delete your previously saved credentials
# at ~/.credentials/gmail-python-quickstart.json
SCOPES = 'https://www.googleapis.com/auth/gmail.send'
CLIENT_SECRET_FILE = 'json/gmail_secrets.json'
APPLICATION_NAME = 'APP NAME GOES HERE'


def get_credentials():
    """Gets valid user credentials from storage.

    If nothing has been stored, or if the stored credentials are invalid,
    the OAuth2 flow is completed to obtain the new credentials.

    Returns:
        Credentials, the obtained credential.
    """
    credential_dir = '.credentials'
    if not os.path.exists(credential_dir):
        os.makedirs(credential_dir)
    credential_path = os.path.join(credential_dir, 'email-sender.json')

    store = Storage(credential_path)
    credentials = store.get()
    if not credentials or credentials.invalid:
        flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
        flow.user_agent = APPLICATION_NAME
        if flags:
            credentials = tools.run_flow(flow, store, flags)
        else: # Needed only for compatibility with Python 2.6
            credentials = tools.run(flow, store)
    return credentials


# Function to read all images in a folder and send them inline
def create_inline_images_message(log, img_dir, sender, to, subject):
    # Read all image filenames
    img_files = glob.glob(os.path.join(img_dir, '*.png'))

    # Holds MIME formatted images
    msg_images = []

    html_body = u'<h1>Latest Performance Reports</h1>'
    for i_f in img_files:
        img_dict = dict(title = 'Image', path = i_f, cid = str(uuid.uuid4()))

        html_body += u'<div dir="ltr"><img src="cid:{cid}" alt="{alt}"><br></div>'.format(alt=html.escape(img_dict['title'], quote=True), **img_dict)

        msg_images.append(attach_image(img_dict))

    # Base version of message
    msg = MIMEMultipart('related')
    msg['Subject'] = subject
    msg['From'] = sender
    msg['To'] = to

    # Create message
    msg_alternative = MIMEMultipart('alternative')      # Message with plain and html alternatives

    # Plaintext (non-HTML) version of the email
    msg_text = MIMEText(u'Image not working - maybe next time', 'plain', 'utf-8')
    msg_alternative.attach(msg_text)

    # HTML version of email
    msg_html = MIMEText(html_body, 'html', 'utf-8')
    msg_alternative.attach(msg_html)

    # Now add images
    for m_i in msg_images:
        msg_alternative.attach(m_i)

    # Attached alternative to original
    msg.attach(msg_alternative)

    return {'raw': base64.urlsafe_b64encode(msg.as_string().encode()).decode()} 


# Function to return formatted image
def attach_image(img_dict):
    with open(img_dict['path'], 'rb') as file:
        msg_image = MIMEImage(file.read(), name = os.path.basename(img_dict['path']))
        msg_image.add_header('Content-ID', '<{}>'.format(img_dict['cid']))
    return msg_image


# Send a gmail message, user_id = 'me' means the currently authenticated user, service is authenticated Gmail instance
def send_message(service, user_id, message):
    try:
        message = (service.users().messages().send(userId=user_id, body=message).execute())
        return message
    except:
        print('An error occurred')


# Read in all metadata used to drive the script
def load_manifest(): 
    return json.load(open('manifest.json'))


# Main code
def main():
    # Load manifest
    manifest = load_manifest()

    # Use the saved credentials file to authenticate and create authenticated service
    credentials = get_credentials()
    http = credentials.authorize(httplib2.Http())
    service = discovery.build('gmail', 'v1', http=http)

    # Create and read log
    log = []

    # Get email addresses
    sender = manifest['globals']['email_sender']
    to = ','.join(manifest['globals']['email_recipients'])

    # Get folders and rename them to prevent race condition then send emails
    all_folders = os.listdir(manifest['globals']['reports_location'])
    eligible_folders = [f for f in all_folders if not f[-5:] in ['_dump', '_work', '_sent']]
    for f in eligible_folders:
        orig_folder_location = os.path.join(manifest['globals']['reports_location'], f)
        working_folder_location = os.path.join(manifest['globals']['reports_location'], f + '_work')
        finished_folder_location = os.path.join(manifest['globals']['reports_location'], f + '_sent')

        os.rename(orig_folder_location, working_folder_location)

        subject = 'Daily Report {}'.format(f)
        message = create_inline_images_message(log, working_folder_location, sender, to, subject)

        sent_message = send_message(service, 'me', message)

        os.rename(working_folder_location, finished_folder_location)

main()

这非常有效,如果我作为用户帐户(例如user1@gmail.com)进行身份验证,并在我进入其Gmail收件箱时使用它们发送电子邮件,则会显示该消息并且图像嵌入在线。但是,如果我使用user1@gmail.com发送到其他帐户(例如user2@gmail.com),当我转到他们的电子邮件收件箱时,图片就不会出现。

在user2的收件箱中,如果我检查了图片占位符,则img标记已移除src。我还注意到,如果我转到Show Original,屏幕顶部会出现SPF,DKIM和DMARC类别。

如果我手动将消息从user1转发到user2,则图像显示为正常,但如果我为user1设置自动转发规则以自动将消息转发给user2,则会再次剥离图像。

我只能假设这是某种安全&#34;功能&#34;这阻止了user2看到图像;我从user1的收件箱中知道电子邮件格式是正确的。

如何让非发送用户看到图片?

0 个答案:

没有答案