跳到正文

当邮件服务器拒绝时 ​

机器翻译

本页由英文原文机器翻译而来,尚未经过母语审校,欢迎在 GitHub 上提出修改。内容如有出入,以英文原文为准。

任务: 即使确认邮件无法发送,订单也必须保存——访问者应该得到说明,而不是一个错误页面。

默认情况下,服务器不接受的 q:mail 会带着服务器给出的原因停止动作。 onerror="continue" 让动作继续,并把结果放在 <name>_result 中:success, 失败时还有 error.message。

这个示例指向一个不存在的邮件服务器,所以每封邮件都会失败——就像真实服务器宕机时一样:

yaml
# Recipe: an order is saved even when the confirmation e-mail cannot be sent.
# The mail server here is deliberately unreachable (nothing listens on port 9),
# so every q:mail fails — as it does when the real server is down.
paths:
  components: ./components
  migrations: ./migrations

datasources:
  db:
    driver: sqlite
    database: ./data/orders.db

mail:
  host: 127.0.0.1
  port: 9
  tls: false
  timeout: 2
  from: shop@example.com
sql
CREATE TABLE orders (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    email TEXT NOT NULL,
    item TEXT NOT NULL
);
xml
<q:component name="Order">
  <q:action name="order" method="POST">
    <q:param name="email" type="email" required="true" />
    <q:param name="item" required="true" />
    <q:query name="saved" datasource="db">
      INSERT INTO orders (email, item) VALUES (:email, :item)
      <q:param name="email" value="{email}" type="string" />
      <q:param name="item" value="{item}" type="string" />
    </q:query>

    <!-- onerror="continue": a refused message does not undo the order -->
    <q:mail name="confirmation" to="{email}" subject="Your order: {item}"
            type="text" onerror="continue">We received your order for {item}.</q:mail>

    <q:if condition="confirmation_result.success">
      <q:redirect url="/" flash="Ordered {item}. A confirmation is on its way." />
    </q:if>
    <q:redirect url="/" flash="Ordered {item}. We could not send the confirmation e-mail." />
  </q:action>

  <h1>Order</h1>
  <q:if condition="flash"><p class="flash">{flash}</p></q:if>
  <form method="POST" action="/?action=order">
    <input name="email" type="email" />
    <input name="item" />
    <button>Order</button>
  </form>
</q:component>

订单在邮件之前插入,提示消息说明结果如何。测试两者都检查——这一行存在,访问者也得到了告知:

xml
<q:test name="the order is saved and the visitor told the e-mail failed" page="/">
  <test:submit action="order" email="ana@example.com" item="Blue mug" />
  <test:expect redirect="/" flash="Ordered Blue mug. We could not send the confirmation e-mail." />
  <test:expect table="orders" count="1" where="email = 'ana@example.com' AND item = 'Blue mug'" />
</q:test>
text
tests/order.test.q
  PASS  the order is saved and the visitor told the e-mail failed
1 passed, 0 failed

在开发中,host: log 可以完全避免这种失败; onerror="continue" 是为真实服务器宕机的那一天准备的。更多内容见 Files & Mail(英文)。

已测试: 本页导入了 examples/cookbook/files-and-mail/mail-server-refuses/ 中的文件, 上面的结果来自运行它们。

MIT 许可证 · 使用 VitePress 构建