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

Python中Stripe支付完成后发送邮件失败问题排查

问题:Stripe收据邮件无法送达排查

背景

  • 基于Flask集成Stripe Checkout的教程开发,数据库包含User表(存储用户邮箱等信息)和Payments表(支持未登录捐赠,存储金额、邮箱字段)
  • 尝试添加Stripe官方收据功能的Python代码后,邮件始终无法送达

相关代码(routes.py)

from flask import Blueprint , render_template, redirect, url_for, request, abort, flash
from app.payment.forms import EmptyForm, EmailForm 
import stripe

payment = Blueprint('payment', __name__, template_folder='templates')

from flask_login import current_user
from app import db
from app.models import User, Payments
from redmail import outlook
import os

@payment.route('/donations', methods = ['POST', 'GET'])
def donations():
    form = EmailForm()
    if form.validate_on_submit():
        price_of_donation_form = str(int(float(request.form["number"]) *100))
        if not price_of_donation_form:
            flash('You did not type in a donation price.')
            return redirect( url_for('payment.donations.html'), code=307 )
        email_form = form.email.data
        payment_db = Payments(price_of_donation=price_of_donation_form, item_name='Donate' , email=email_form) 
        db.session.add(payment_db) 
        db.session.commit()
        flash('donations are successful')
        return redirect(url_for('payment.order', item_name_db=payment_db.item_name), code=307)
    return render_template('stripe_payment/donations.html',  form=form, title=' Give donations')

@payment.route('/order/<item_name_db>', methods=['POST'])
def order(item_name_db):
    payment_db = Payments.query.filter_by(item_name=item_name_db).first_or_404()

    checkout_session = stripe.checkout.Session.create(   
        line_items=[
            {
                'price_data': {
                    'product_data': {
                        'name': payment_db.item_name, 
                    },
                    'unit_amount': payment_db.price_of_donation,
                    'currency': "usd",
                },
                'quantity': 1,
            },
        ], 
        customer_email=payment_db.email,
        payment_method_types=['card'],
        mode='payment',
        success_url=request.host_url + 'order/success',
        cancel_url=request.host_url + 'order/cancel',
    )

        # send email after payment/donation
        stripe.PaymentIntent.create
    (
        amount=payment_db.price_of_donation,
        currency="usd",
        payment_method_types=["card"],
        receipt_email=payment_db.email,
        description="3% of your purchase goes toward our ocean cleanup effort!",
    )

    return redirect(checkout_session.url)

@payment.route('/order/success')
def success():
    return render_template('success.html', data=data)

@payment.route('/order/cancel')
def cancel():
    return render_template('cancel.html')

问题排查与修复方案

1. PaymentIntent创建时机与关联错误

你在用户未完成支付时就手动创建了PaymentIntent,但这个Intent和用户实际通过Checkout完成的支付没有关联,不会被触发支付,自然不会触发收据邮件。

使用Stripe Checkout时,系统会自动创建关联的PaymentIntent,无需手动调用stripe.PaymentIntent.create。

2. 代码语法错误

stripe.PaymentIntent.create的调用存在缩进和语法错误,导致代码无法正常执行:

# 错误写法
stripe.PaymentIntent.create
(
    # 参数...
)

正确写法应该是:

stripe.PaymentIntent.create(
    amount=payment_db.price_of_donation,
    currency="usd",
    payment_method_types=["card"],
    receipt_email=payment_db.email,
    description="3% of your purchase goes toward our ocean cleanup effort!",
)

3. 正确的收据配置方式

方式一:让Stripe自动发送收据

  1. 先在Stripe后台开启自动收据:进入设置→客户设置→收据,确保「成功付款后自动发送收据」已启用
  2. 在创建Checkout Session时,明确指定receipt_email参数(已传customer_email的情况下,Stripe会默认使用该邮箱,但明确指定更稳妥):
checkout_session = stripe.checkout.Session.create(   
    # 其他参数...
    customer_email=payment_db.email,
    receipt_email=payment_db.email,  # 新增:指定收据接收邮箱
    # 其他参数...
)

方式二:通过Webhook触发自定义邮件

如果需要发送自定义邮件(而非Stripe默认收据),需监听checkout.session.completed事件:

  1. 在Stripe后台配置Webhook端点,指向你的Flask接口(如/webhook/stripe)
  2. 在Flask中实现Webhook处理函数,收到支付成功事件后发送邮件:
@payment.route('/webhook/stripe', methods=['POST'])
def stripe_webhook():
    payload = request.get_data(as_text=True)
    sig_header = request.headers.get('Stripe-Signature')
    event = None

    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, os.environ.get('STRIPE_WEBHOOK_SECRET')
        )
    except ValueError as e:
        return '', 400
    except stripe.error.SignatureVerificationError as e:
        return '', 400

    if event['type'] == 'checkout.session.completed':
        session = event['data']['object']
        # 获取支付信息,发送自定义邮件
        email = session['customer_email']
        # 用redmail发送邮件的逻辑
        outlook.send(
            subject='感谢你的捐赠',
            receivers=[email],
            html='<h1>捐赠收据</h1><p>你的捐赠金额为:...</p>'
        )

    return '', 200

4. 额外排查点

  • 检查Stripe日志:进入Stripe后台→开发→日志,查看是否有PaymentIntent错误或邮件发送失败记录
  • 测试环境限制:测试模式下,Stripe仅会向测试邮箱(如test@example.com)发送收据,真实邮箱无法收到,需切换生产模式或使用指定测试邮箱
  • 验证邮箱格式:确认Payments表中存储的邮箱格式有效,无拼写错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 09:07:57