我们生活中接触到的很多互联网服务都有定时发送个性化邮件提醒的功能,比如信用卡公司会在客户每个月的账单日发出还款提醒,还有项目管理类应用会定期给用户发送即将到期的待办事项的汇总。作为应用开发者,我们该如何去实现这类功能呢?
很多邮件群发服务商允许你设定时间间隔来自动向用户发送邮件,不过这类服务的缺点是内容无法做到高度定制化。通常你可以在邮件模版中插入能够在用户列表里找到的姓名、称谓等资料,但这些资料都是静态的。如果我们希望邮件内容可以基于用户的实际使用数据来动态生成(比如在还款提醒里面插入还款金额),那么这其中一定需要某种机制从应用的数据库中拉取与用户相关的数据(通常还需进行一定的计算),这是基于模版的群发服务做不到的。另外如果需要在不同时间向不同用户发送提醒(比如不同的信用卡客户有不同的账单日,或者应用允许用户自定义接收提醒的时间和频率),那么如何管理发送时间也成了难题。
所以如果想要给用户个性化的提醒,就需要独立于邮件群发服务商之外维护一个定时器,这个定时器应该能够主动访问应用数据库并基于获取到的数据执行特定的代码;与此同时,选用一个支持通过 API 调用来传入邮件内容和收件人的邮件服务商,让前面的定时器在需要发送邮件时将相关数据传入 API。
代码从数据库获取数据,然后基于这些数据编写邮件
我们制作了一个展示如何实现这些功能的 Demo。这个 Demo 包含了一个最基本的 Todo 应用,用户可以创建 Todo 项目并为每个项目设置一个截止时间,Todo 会被保存在 LeanCloud 的数据存储服务中。这个 Demo 还包含一个云函数(可以在云端执行的代码),用于查询是否有在接下来一定时间内到期但尚未完成的项目,如果有的话就会调用 SendGrid 的 API 给一个固定地址发送一封包含这些项目的邮件。这个云函数会被托管在 LeanCloud 云引擎上面,每隔一段时间执行一次。
准备工作
为了能够顺利运行 Demo,请确保你已经分别拥有 LeanCloud 和 SendGrid 的帐户。如果还没有的话,可以前往它们各自的官网进行注册:
LeanCloud:https://www.leancloud.cn/
SendGrid:https://sendgrid.com/
前端部分
先将 Demo 克隆到本地,用编辑器打开 index.html,这里包含了 Todo 应用的前端部分。它满足了以下需求:
- 用户可以创建 Todo 项目。创建 Todo 时,需提供标题和截止时间。
- 应用通过一个列表展示出所有的 Todo,包括它们的标题和截止时间。
- 每个 Todo 带有一个复选框用于在「未完成」和「已完成」两种状态间切换。Todo 在创建后默认为「未完成」状态。
- 每个 Todo 带有一个「删除」按钮用于将其从列表中删除。
代码是基于 Vue.js 编写的。以下是对各部分的解释:
-
< h2 >新建 Todo< /h2 >
下方的表单与data.newTodo
中的数据绑定。 - add 方法会在「创建」被点击时触发,它会从 data.newTodo 中获取数据,创建一个 Todo 对象(该对象具有一个 title 属性表示标题,一个 due 属性表示截止时间,还有一个 completed 属性表示是否已完成,默认为 false),并将其保存到 LeanCloud 云端。
- fetchTodos 方法会从 LeanCloud 云端获取所有 Todo 对象并用它们替换掉 data.todos。data.todos 中的数据会被渲染在
< h2 >Todo 列表< /h2 >
下方。 - toggleCompleted 方法会在某一个 Todo 项目的复选框被点击时触发,它会根据复选框的状态更新对应的 Todo 对象的 completed 属性(已勾选为 true,未勾选为 false),并将修改后的对象保存到 LeanCloud 云端。
- remove 方法会在某一个 Todo 项目的「删除」按钮被点击时触发,它会从 LeanCloud 云端删除对应的 Todo 对象。
- fetchTodos 会在页面加载完成后运行一次来将数据库中已有的 Todo 项目拉取到前端。add、toggleCompleted、remove 在完成各自的操作后也都会触发一次 fetchTodos 来刷新前端的 Todo 列表。
LeanCloud 数据存储 SDK 的用法可参考官方指南。
在运行 Demo 之前,让我们先去 LeanCloud 创建一个应用用于存储数据。点击 LeanCloud 控制台首页的「创建应用」,随便填写一个应用名,然后点击「创建」,之后点击应用的名字进入应用管理界面。点击左侧「设置」里面的「应用 Keys」找到「AppID」、「AppKey」和「REST API 服务器地址」并将它们分别填入 index.html 中的 appId、appKey 和 serverURLs,然后保存文件。现在你可以直接在浏览器中打开这个文件并尝试我们前面提到的那些功能。试着随便填入一个标题、日期、时间并点击「创建」,如果「Todo 列表」中出现了你输入的内容,证明这条 Todo 已经成功保存到 LeanCloud。现在回到 LeanCloud 的控制台并点击左侧的「存储」,然后点击「Todo」这个 Class,你就能看到刚刚创建的所有 Todo:
Todo 表中含有刚刚创建的 Todo 项目
云函数
接下来我们来准备云函数。我们希望每隔 30 秒查询是否有在接下来一天(24 小时)内到期但未完成的项目,如果有的话则发出邮件,那么实现思路就是:
- 编写一个查询,查找
due
位于当前时间一天之内且completed
为false
的Todo
对象。 - 如果该查询返回 1 个或多个对象,则调用 SendGrid 的 API 发送邮件,邮件内容基于这些对象包含的数据生成。
- 将以上逻辑打包成一个云函数。
- 每隔 30 秒运行一次该云函数。
上述逻辑的第 1 至 3 条已经在 cloud.js
中名为 checkTodos
的云函数中实现好,不过为了能够正常发送邮件,我们还需要从 SendGrid 获取一个 API Key。
让我们打开 SendGrid 的控制台,点击左侧的「Email API」,进入「Integration Guide」,选择「Web API」,然后选择「Node.js」:
SendGrid 界面截图
在接下来的界面中的第二步随便填入一个名字,然后点击「Create Key」,你就能得到一个 API Key:
SendGrid 界面截图
将其填入 cloud.js
中的 sgMail.setApiKey
。另外在后面的 to
中填入你的邮箱地址,这样我们稍后测试代码时,你就可以收到并查看应用发出的邮件。
至此,我们这个 Todo 应用的前端和后端的代码已经就绪。我们最后要做的,是将其部署到 LeanCloud 云引擎上,并设置定时任务。
部署并设置定时任务
如果你还没有安装 LeanCloud 命令行工具,请根据这里的指引进行安装。安装并登录好 LeanCloud 账号后,将本地的项目和 LeanCloud 上的应用进行关联,然后运行 lean deploy
进行部署。
部署完成后,打开 LeanCloud 控制台,点击左侧的「云引擎」并进入「定时任务」,然后点击「创建定时任务」。随便填写一个名称,在「请选择函数」下拉列表中选择「checkTodos」,勾选「循环任务间隔时长」并在下方填入「30」,最后点击「保存」。
大功告成!你现在可以试着创建几个在当前时间 24 小时内到期的 Todo 项目,稍等片刻应该就能收到类似这样的通知邮件了:
列出 Todo 项目的邮件
注意:如果不对定时任务进行其他操作,那么它将一直运行下去。请确保在每次测试完成后暂停或删除定时任务。
现在你已经掌握了如何定时向用户发送包含定制化内容的邮件。其实定时任务这个功能还有很多其他玩法,比如定时清理垃圾数据、定期生成统计报表等等。如果你觉得这是个不错的功能,不妨自己动手基于 Demo 里面的代码进行一些修改,尝试做一些更有趣、更实用的功能。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。