前言
最近帮朋友做了一个点单的微信小程序,使用了云开发,还是挺香的。
客户点单需要提醒老板娘,想到了两种方案:
- 短信
- 邮箱
最后选择了邮箱,免费的谁不爱呢。
大致流程是客户提交订单的逻辑在云函数中处理,提交订单时将订单信息发送给老板娘的邮箱。
先看下最终效果:
准备
首先需要准备一个邮箱,开通IMAP/SMTP服务,获得授权码。此处以QQ邮箱为例:
代码
发送邮件云函数
发送邮件需要用到nodemailer 库。
创建一个云函数 sendmail:
安装 nodemailer:
在 package.json 中添加 nodemailer 依赖,本地调试或部署时可自动安装。
也可进入到 sendmail 根目录,执行
npm install nodemail 或 yarn add nodemail
{
"name": "sendmail",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"wx-server-sdk": "~2.5.3",
"nodemailer": "^6.6.3"
}
}
sendmail 云函数代码
const cloud = require('wx-server-sdk')
const nodemailer = require('nodemailer')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
/*
message: 调用云函数时传入的数据,此处传入的是邮件信息
{
from: "sender@server.com", // 发件人邮箱
to: "receiver@sender.com", // 收件人邮箱
subject: "邮件的标题",
text: "邮件纯文字内容",
html: "<p>可以发送 HTML</p>"
}
*/
exports.main = async (message, context) => {
const sendEmail = nodemailer.createTransport({
host: 'smtp.qq.com', // SMTP 服务器地址,此处是 QQ邮箱
port: 465, // 端口号,通常为465,587,994,不同的邮件客户端端口号可能不一样
secure: true, // 如果端口是465,就为true;如果是其它就填false
auth: {
user: 'xxx@qq.com', // 邮箱账号,填写已开启SMTP服务的邮箱地址即可
pass: '此处填写之前取得的授权码' // 邮箱密码,不同的邮件系统可能机制不一样,QQ 邮箱和网易邮箱为邮箱授权码
}
})
const res = await sendEmail.sendMail(message)
return res
}
处理订单云函数
以下是订单的字段结构:
{
"_id": "2d44d6c2610bc57902d23b2771c2861b",
"address": "成都市春熙路边",
"consignee": "李白",
"datetime": 1628161200000,
"phone": "18911112222",
"products": [
{
"_id": "2d44d6c26100ff580072a06244a35695",
"count": 1,
"img": "cloud://yulu-z3s06.7975-yulu-z3s06-1301369817/cloudbase-cms/upload/2021-08-02/fgfbz3qiw53xggf6hq4ypbs8b515v6py_.jpg",
"price": 166,
"selectedSku": {
"price": 166,
"spec": [
"六寸",
"淡奶油"
]
},
"title": "韩式简约风"
},
],
"remark": "",
"totalCount": 2,
"totalPrice": 292,
"status": "制作中",
"_createTime": 1628161407261
}
直接上代码:
const cloud = require('wx-server-sdk')
const dayjs = require('dayjs')
// 初始化 cloud
cloud.init({
// API 调用都保持和云函数当前所在环境一致
env: cloud.DYNAMIC_CURRENT_ENV
})
exports.main = async (order, context) => {
try {
const db = cloud.database()
const _ = db.command
// 购买的商品销量增加
order.products.forEach(({ _id, count }) => {
db.collection('product')
.doc(_id)
.update({
data: {
sales: _.inc(count)
}
})
})
// 向数据库添加订单
const data = await db.collection('order').add({
data: {
...order,
status: '制作中',
_createTime: new Date().getTime()
}
})
// 订单创建成功发邮件
if (data._id) {
// 捕获错误,避免发邮件出错影响导致前端提交订单时意外报错
try {
// 邮件内容
const message = {
from: 'xxxx@qq.com',
to: 'xxx@qq.com',
subject: '老板娘,来新的订单啦!',
text: '新订单',
html: createHtml(order)
}
// 云函数中可以调用其它云函数,此处调用之前创建的 sendmail
cloud.callFunction({ name: 'sendmail', data: message })
} catch (error) {}
return data
}
throw new Error()
} catch (error) {
return {
code: -1,
msg: '提交失败,请稍后重试'
}
}
}
/**
创建订单信息邮件的 HTML,可以编写自己喜欢的样式
*/
function createHtml ({
consignee,
phone,
address,
datetime,
remark,
products,
totalPrice
} = {}) {
return `
<div style="display: flex; justify-content: center; align-items: center; padding: 40px 0;">
<div
style="padding: 20px; color: #333333; background-color: #fff; border-radius: 10px; box-shadow: 0 0 10px rgba(128, 128, 128, 0.3); letter-spacing: 1px;"
>
<div style="line-height: 1.6;">
<div>联系人:${consignee}</div>
<div>电话:${phone}</div>
<div>地址:${address}</div>
<div>送达时间:${dayjs(datetime).format('YYYY-MM-DD HH:mm')}</div>
</div>
<div
style="margin-top: 15px; border-top: 2px dashed #e9e9e9; border-bottom: 2px dashed #e9e9e9;"
>
${products
.map(({ title, count, price, selectedSku }) => {
return `<div style="display: flex; padding: 10px 0;">
<div style="flex: 1;">${title}${
selectedSku ? '(' + selectedSku.spec.join('+') + ')' : ''
}</div>
<div style="width: 60px; text-align: right;">×${count}</div>
<div style="width: 60px; color: red; text-align: right;">¥${price}</div>
</div>`
})
.join('')}
</div>
<div
style="display: flex; justify-content: space-between; margin-top: 15px;"
>
<div>总金额</div>
<div style="color: red;">¥${totalPrice}</div>
</div>
<div style="margin-top: 10px; line-height: 1.6;">备注:${remark}</div>
</div>
</div>`
}
部署
可现在本地调试后再上传部署。
最后
有需要的小伙伴可以直接复制代码使用。
感谢观看,不足之处或有疑问欢迎评论区讨论。