高效获取信息之RSS邮件补充

RSS mail supplement for efficient information acquisition.

来自:Pixiv 画师(MORNCOLOUR

 

 

 

 

 

前言

在上一篇高效获取信息文章中,介绍了烧制RSS和邮件转化RSS。之前的思路是【自动化服务→Google sheets→GS→构造rss格式】,这里再来补充一个订阅邮件的方式,相比之前的会简单点,易用性更高。

 

 

 

 

 

需要用到的服务

  • CloudFlare Workers(其他云函数服务亦可)
  • testmail.app(自动化邮件测试服务)

 

 

 

 

 

操作流程

(1)创建testmail服务

注册登录testmail.app,并创建一个命名空间(免费方案只能建一个)。获得一个测试邮件,格式为 {NameSpace}.{Tag}@inbox.testmail.app 。

(2)创建云函数

怎么创建自行Google,代码如下:

const allowedTags = ["TAG"];
const testmailNamespace = "NAMESPACE";
const testmailToken = "TOKEN";
const deployUrl = "LINKS";

class TestMail {
  static testmailApi = "https://api.testmail.app/api/graphql";

  static async getMails(tag) {
    const query = `{
      inbox (
        namespace: "${testmailNamespace}"
        tag: "${tag}"
        limit: 99
      ) {
        emails {
          id
          subject
          html
          from
          timestamp
          downloadUrl
          attachments {
            cid
            downloadUrl
          }
        }
      }
    }`;

    const init = {
      method: "POST",
      headers: {
        "content-type": "application/json;charset=UTF-8",
        Authorization: `Bearer ${testmailToken}`,
        Accept: "application/json",
      },

      body: JSON.stringify({
        operationName: null,
        query,
        variables: {},
      }),
    };
    return fetch(this.testmailApi, init);
  }
}

addEventListener("fetch", (event) => {
  event.respondWith(handleRequest(event));
});

/**
 * Respond to the request
 * @param {Event} event
 */
async function handleRequest(event) {
  const { request } = event;
  let url = new URL(request.url);
  // parse tag
  const requestTag = url.pathname.substring(1);
  if (!allowedTags.includes(requestTag)) {
    return new Response("Unknown tag.", { status: 403 });
  }

  let mailResponse = await TestMail.getMails(requestTag);
  if (mailResponse.status != 200) {
    return new Response("Internal Server Error.", { status: 500 });
  }
  let data = await gatherResponse(mailResponse);
  let responseXML = await makeRss(data.data.inbox.emails, requestTag);
  response = new Response(responseXML, {
    status: 200,
    headers: {
      "content-type": "application/xml; charset=utf-8",
    },
  });
  response.headers.append("Cache-Control", "max-age=600");
  return response;
}

/**
 * gatherResponse awaits and returns a response body as a string.
 * Use await gatherResponse(..) in an async function to get the response body
 * @param {Response} response
 */
async function gatherResponse(response) {
  const { headers } = response;
  const contentType = headers.get("content-type");
  if (contentType.includes("application/json")) {
    return await response.json();
  } else if (contentType.includes("application/text")) {
    return await response.text();
  } else if (contentType.includes("text/html")) {
    return await response.text();
  } else {
    return await response.text();
  }
}

async function makeRss(emails, tag) {
  let items = emails.map((value) => {
    if (value.attachments.length > 0) {
      for (let i of value.attachments) {
        // update the image link
        value.html = value.html.replace(`cid:${i.cid}`, i.downloadUrl);
      }
    }
    return `<item>
    <title><![CDATA[${value.subject}]]></title>
    <description><![CDATA[${value.html}]]></description>
    <pubDate>${new Date(value.timestamp).toGMTString()}</pubDate>
    <guid isPermaLink="false">${value.id}</guid>
    <link>${value.downloadUrl}</link>
    <author><![CDATA[${value.from}]]></author>
</item>`;
  });

  return `<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
        <title><![CDATA[${tag}邮件订阅]]></title>
        <link>${deployUrl + tag}</link>
        <atom:link href="${
          deployUrl + tag
        }" rel="self" type="application/rss+xml" />
        <description><![CDATA[${tag}邮件订阅]]></description>
        <generator>mail2rss</generator>
        <webMaster>lengthmin@gmail.com (Artin)</webMaster>
        <language>zh-cn</language>
        <lastBuildDate>${new Date().toGMTString()}</lastBuildDate>
        <ttl>300</ttl>
        ${items.join("\n")}
    </channel>
</rss>`;
}

其中TAG换成自己设置的一串字符(其作用相当于后面调用时的请求路径),NAMESPACE换成testmail的NameSpace,STOKEN换成testmail的API keys,LINKS则是当前workers的调用地址或是设置自己的域名https://xxx.abc.com(细节自行Google)。

那么后面要用到的RSS地址为:workers的调用地址+TAG。假设我的Tag的ribfg,域名为jiemo.top,那么我的订阅地址将是https://testmail.jiemo.top/ribfg。

(3)连接到自己的邮箱【设置转发】

以Gmail为例,设置中设置转发到testmail的测试邮箱,即{NameSpace}.{Tag}@inbox.testmail.app

-设置转发-

完成转发需要向测试邮箱发送一封验证邮件,如何查看这个验证邮件。来到testmail控制台。

-点击clickhere-

查看验证邮件内容,点击其中的验证链接完成转发设置。

(4)测试转发

使用另外的邮箱向Gmail发送邮件,clickhere可以查看到发送的邮件即可。自行操作

(5)订阅邮箱

订阅前可以先手动访问一下RSS地址(https://testmail.jiemo.top/ribfg)

-发送的邮件包含其中-

-订阅它,结束-

 

 

 

 

 

结语

cloudflare workers 每天免费请求量 100,000 次。
testmail.app 免费版每个月可以接收 100 封邮件,邮件可以保存一天。

也就是说,只要你的RSS阅读器请求频率小于一天,你都能毫无遗漏的接收每一封邮件。

此法也是0成本的方案。

 

 

 

 

发表回复