You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

本地正常服务器报错TypeError: Could not guess image MIME subtype求助

问题:Gramex邮件服务嵌入图片时出现TypeError: Could not guess image MIME subtype

问题场景

使用Gramex capture API捕获图表生成PNG图片,通过<img>标签嵌入邮件模板,本地环境邮件发送正常,但服务器端触发以下错误:

TypeError: Could not guess image MIME subtype

已确认服务器上图片为PNG格式且路径正确,核心业务代码如下:

def send_email(handler):
    user = handler.args.get('user', ['None'])[0]
    chart_selector = ['.bar-chart', '.donut-chart', '.world_map', '.headerImg']
    folder = os.path.dirname(os.path.abspath(__file__))
    mailer = service.email["galaxy-email-smtp"]
    try:
        yield service.threadpool.submit(
            load_file, user, chart_selector
        )
    except Exception as e:
        print("An error occurred:", str(e))
    temp_file = gc.open('email.digest.template.formatted.html', 'template')
    file_path_barchart = os.path.join(folder, 'downloaded1.png')
    file_path_donutchart = os.path.join(folder, 'downloaded2.png')
    file_path_worldmap = os.path.join(folder, 'downloaded3.png')
    file_path_header = os.path.join(folder, 'downloaded4.png')
    html_content = temp_file.generate(data={"handler": handler}).decode('utf-8')
    mailer.mail(
        sender=<email>,
        to=user,
        subject=<subject>,
        html=html_content,
        images={
            "headerImg": file_path_header,
            "ricoImg": os.path.join(folder, 'assets/img/rico.png'),
            "bar-chart-img": file_path_barchart,
            "donut-chart-img": file_path_donutchart,
            "world_map": file_path_worldmap,
        },
    )
    return "email has been sent"


def load_file(user, chart_selector):
    url = <url> + user
    for index, each_chart_selector in enumerate(chart_selector):
        file_name = f"downloaded{index+1}.png"  # Generate the file name
        chart_capture = capture.png(
            url, selector=each_chart_selector, scale=2, timeout=60
        )
        with open(file_name, "wb") as f:
            f.write(chart_capture)

错误栈指向Gramex的emailer.py中创建MIMEImage时未指定_subtype参数:

for name, path in images.items():
    with open(path, 'rb') as handle:
         img = MIMEImage(handle.read())
         img.add_header('Content-ID', f'<{name}>')
         html_part.attach(img)

手动修改为img = MIMEImage(handle.read(), 'png')后问题解决,询问是否有官方配置方式指定图片subtype。


原因分析

Python的email.mime.image.MIMEImage默认会尝试通过图片内容自动推断MIME子类型,但服务器环境可能缺少文件类型识别依赖(如python-magic),或者捕获的PNG图片头部信息不完整,导致无法自动识别,从而触发该错误。本地环境通常依赖完整,所以能正常识别。


解决方案

目前Gramex官方邮件服务的images参数仅支持传入文件路径,没有直接配置MIME子类型的选项。可以通过以下两种方式解决:

1. 临时修改Gramex源码(快速解决)

如你已经尝试的,修改gramex/services/emailer.py中创建MIMEImage的代码,指定_subtype='png':

img = MIMEImage(handle.read(), _subtype='png')

注意:这种方式会影响所有通过该Gramex实例发送的图片邮件,若有其他格式图片需要发送,需额外判断文件扩展名来动态指定subtype。

2. 自定义邮件构建逻辑(更灵活)

绕过Gramex邮件服务的images参数,手动构建MIME邮件并嵌入图片,精确控制每个图片的subtype:

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage

def send_email(handler):
    # ... 原有代码逻辑 ...
    html_content = temp_file.generate(data={"handler": handler}).decode('utf-8')
    
    # 手动构建多部分邮件
    msg = MIMEMultipart('related')
    msg['From'] = <email>
    msg['To'] = user
    msg['Subject'] = <subject>
    
    # 添加HTML部分
    html_part = MIMEText(html_content, 'html', 'utf-8')
    msg.attach(html_part)
    
    # 手动嵌入图片,指定subtype
    images = {
        "headerImg": (file_path_header, 'png'),
        "ricoImg": (os.path.join(folder, 'assets/img/rico.png'), 'png'),
        "bar-chart-img": (file_path_barchart, 'png'),
        "donut-chart-img": (file_path_donutchart, 'png'),
        "world_map": (file_path_worldmap, 'png'),
    }
    for cid, (path, subtype) in images.items():
        with open(path, 'rb') as f:
            img = MIMEImage(f.read(), _subtype=subtype)
            img.add_header('Content-ID', f'<{cid}>')
            img.add_header('Content-Disposition', 'inline', filename=os.path.basename(path))
            msg.attach(img)
    
    # 使用Gramex邮件服务发送自定义构建的邮件
    mailer.send(msg)
    return "email has been sent"

3. 提交Feature Request

可以在Gramex的官方代码仓库提交Feature Request,建议为mail()方法的images参数支持传入包含路径和subtype的元组,或者添加额外参数指定默认subtype,无需修改源码即可解决问题。


内容的提问来源于stack exchange,提问作者Lahari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 12:55:10