使用 Node 和 Dropbox 实现电子邮件自动化

2025-06-08

使用 Node 和 Dropbox 实现电子邮件自动化

我选择懒人来做难事。因为懒人总能找到轻松的方法。——比尔·盖茨

我觉得这句话恰恰诠释了我热爱程序员这份职业的原因。我们通常很懒,但却很擅长解决问题,包括我们自己的问题!有时候,这甚至可能不需要写代码,但大多数时候,你可以认为我们确实写过代码🤓

好了,我最近遇到的问题是:我妈妈需要每两周给她的客户发一次发票,但她对电脑不太懂。发票是手写的,需要扫描成PDF格式。因为我现在不常在家,所以姐姐帮她扫描了,但她懒得整理邮件,就把发票加到我的Dropbox里,这样我终于可以发给客户了。

我讨厌整个过程......并且收到“您发送了发票吗?”的短信。

对于我来说涉及的步骤是:

  1. 从 Dropbox 下载文件
  2. 登录妈妈的电子邮件帐户
  3. 给客户写一封非常普通的电子邮件
  4. 附加下载的文件
  5. 发送电子邮件

解决方案:自动化所有事情!

Javacript/Node 来救援!

JavaScript 和 Node 似乎最适合我的解决方案,因为我知道我需要运行一个服务器端应用程序来定期检查我的 Dropbox 以查找文件。我也正在努力成为一名全栈开发人员,所以我知道这将是一次很棒的学习练习。

最近我完成了Wes Bos 的“学习 Node”课程,这对我最终解决方案的设计选择有很大帮助。这包括但不限于:Node、ES6、PromisesNodemailerNode Cron以及用于持续部署的 Shell 脚本(我将在下一篇文章中进一步探讨这些内容——请在 Twitter 上关注我!)。

我不会过多地介绍这个应用程序的具体细节,因为你可以在 GitHub 上直接查看。但是,我想进一步解释一下我遇到的问题,如何改进这个应用程序,以及哪些实用程序让编写这个应用程序变得如此有趣!

Promises 和 Dropbox API

之前,我曾使用 PHP 开发过一个 Dropbox API应用,可以随机选择一组照片并显示在网页上。这个应用比较基础,感觉不太对劲,因为我们只是用 curl 函数调用 API,而且最近我尽量少用 PHP。

在构建发票应用程序时,我发现 Dropbox 已经创建了一个JavaScript SDK来与 API 交互。这很令人兴奋,而当我阅读文档发现它是基于 Promise 的,更是兴奋不已!Promise 意味着你可以轻松地串联几个 API 调用来获取所需的数据或执行所需的操作,几乎不费吹灰之力。

以下是一个用于下载文件的 Promise 链示例。它假设你传递了文件的路径,而你可以通过其他 API 调用/Promise 轻松获取该路径。

const Dropbox = require('dropbox');
const dbx = new Dropbox({ accessToken: process.env.ACCESS_TOKEN });

exports.getFile = function (path) {

  const file = dbx.filesDownload({ path: path })
    .then(function (response) {
      return response;
    })
    .catch(function (error) {
      console.log('Error downloading the file ❎');
      return Promise.reject(error);
    });

  return file;
};
Enter fullscreen mode Exit fullscreen mode

真不敢相信这不是黄油!这么简单,文件却这么丰富。🐕

为了证明我不是在虚张声势,我创建了另一个函数,在邮件发送后调用。这会将 Dropbox 中的文件移动到另一个文件夹,以表明该发票已发送。

exports.archiveFile = function (path, subFolderName) {
  const archivedFile = dbx.filesMove({
    from_path: path,
    to_path: '/sent/' + subFolderName + path,
    allow_shared_folder: true,
    autorename: true,
    allow_ownership_transfer: true
  })
    .then(function (fileMove) {
      console.log('File ' + fileMove.name + ' archived successfully! 🗳️');
      return fileMove;
    })
    .catch(function (error) {
      console.log('Error archiving the file 💥');
      return Promise.reject(error);
    });

  return archivedFile;
};
Enter fullscreen mode Exit fullscreen mode

在这里我传递客户端名称,这subFolderName意味着您将获得一个组织良好的文件路径,例如/sent/client-name/INV0001.PDF

但是电子邮件怎么办?

哦对了,在归档文件之前,我们当然要先发送邮件。这封邮件的创建过程涉及几个小步骤,但发送过程非常简单。

由于我妈妈有多个客户,所以解决方案需要兼具某种形式的可重用性和可扩展性。我为每个客户创建了一个 JSON 文件,如下所示:

{
  "name": "Recipient",
  "email": "test@email.com",
  "subject": "An interesting Email Subject",
  "text": "Hi John Doe,\n\nInvoice attached.\n\nKind Regards,\nJane Doe",
  "file-prefix": "INV"
}
Enter fullscreen mode Exit fullscreen mode

这样可以确保 Dropbox 发送的每个文件都会根据其文件名前缀进行邮寄,从而允许每个客户在邮件中使用不同的姓名、邮箱地址、主题或文本。这也意味着,如果她有了更多客户,只需创建新的 JSON 文件即可将其纳入自动化流程。🚂

使用上述数据和对 Dropbox API 的调用,我们可以构建电子邮件并使用Nodemailer发送它。

通过 Nodemailer 发送电子邮件的代码是一个带有一些选项参数的函数调用(如下所示)。这些参数会被传递,然后与传输函数结合使用,该函数的大部分配置都是使用环境变量设置的(因为你不希望有人向你发送垃圾邮件或获取你的 SMTP 凭据)。

在这个应用程序中,我使用二进制文件流/缓冲区添加了文件,这听起来比实际或实际需要的要复杂得多。实际上,它只是意味着我们从 Dropbox 获取文件的二进制版本,将其保存为变量,将其传递给缓冲区,然后它就变成了文件附件。

 ...

 const sendInvoice = attachedFile.searchFilePath(filePrefix)
      .then(function (filePath){
        foundFilePath = filePath;
        const file = attachedFile.getFile(filePath);
        return file;
      })
      .then(function (file) {
        const mailPromise = mail.send({
          email: recipient.email,
          subject: recipient.subject,
          text: recipient.text,
          attachments: {   // binary buffer as an attachment
            filename: file.name,
            content: new Buffer(file.fileBinary, 'binary'),
            encoding: 'binary'
          }
        });
        return mailPromise;
      })

  ...
Enter fullscreen mode Exit fullscreen mode

瞧!只需几个函数调用,应用程序的大部分功能就完成了。如果mailPromise解析成功,我们的电子邮件就会发送。

要在开发过程中测试电子邮件发送,使用Mailtrap之类的服务可以节省很多时间,因为它是免费的,而且不会填满任何人的收件箱😆

一旦投入生产,我就会将其改用Mailgun,因为您每月可以免费发送最多 10,000 封电子邮件!

自动化🤖

因此看起来该应用程序涵盖了您之前提到的所有步骤......但是什么让它自动化呢?

其实不需要太多,只需使用cron每小时运行一次(或根据需要多次运行)。cron 是“向操作系统或服务器发出的命令,用于在指定时间执行的作业”。在本例中,应用程序会检查是否有要发送的文件。如果有,则执行应用程序的其余部分;如果没有,则不执行任何操作。如前所述,承诺链使这个过程变得轻而易举。

就像所有事情一样,总有改进的空间。cron 可以通过仅在文件上传后运行该函数来移除,显然你不能仅仅通过 API 来实现这一点,但聪明人应该已经意识到可以使用 webhook 来实现(不过那是下次再说了)。

结论

这个项目超级棒!我学到了很多东西,从 Node 到 Shell 脚本,从 Cron 任务到 Promises。像这样的小项目真的能推动你作为一名开发者不断进步。它们能让你成为你想要的完美主义者,并创造出一些东西来改善你的生活(有时也会改善他人的生活),而且方式多种多样。

鏂囩珷鏉ユ簮锛�https://dev.to/daviddeejjames/email-automation-with-node-and-dropbox-593o
PREV
Redux 是模式的一半(2/2)
NEXT
使用 Carbon 共享代码示例