
天天
上一篇我们已经拿到了发票的信息,并且保存到了 Google 表格中,接下来,我们要把关键信息,发送到我们的邮箱中。
https://appstore.lazycat.cloud/#/shop/detail/cloud.lazycat.app.n8n
### 提取邮箱地址
这一步需要把第一步中,我们输入的邮箱提取出来,参考代码
```
const raw = $('When chat message received').first().json.chatInput|| "";
// 匹配第一个邮箱格式
const match = raw.match(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/);
return [
{
json: {
email: match ? match[0] : null
}
}
];
```
执行后,可以看到能正常提取

### if判断
这一步,如果我们识别出来了邮箱,并且不为空的话,就执行下一步

### 发邮件
发邮件之前,可以把我们前面的节点名称改一下,方便我们看

回到 Google [控制台](https://console.cloud.google.com)
点击 API 和服务

在这里搜索 Gmail

启用 API 的权限

这时候,回到 n8n,新建一个凭证
输入客户端 id 和密钥

授权成功会有提示

操作选择 send,邮箱就是我们识别出来的邮箱

邮件类型选择 html,message 参考下面的代码
```
{{ $('GoogleSheets').first().json["发票标题"] || "发票" }}
发票号码:{{ $('GoogleSheets').first().json["发票号码"] || "" }}
开票日期:{{ $('GoogleSheets').first().json["开票日期"] || "" }}
购方信息
名称:{{ $('GoogleSheets').first().json["购方名称"] || "" }}
税号:{{ $('GoogleSheets').first().json["购方税号"] || "" }}
备注:{{ $('GoogleSheets').first().json["购方备注"] || "" }}
销方信息
名称:{{ $('GoogleSheets').first().json["销方名称"] || "" }}
税号:{{ $('GoogleSheets').first().json["销方税号"] || "" }}
商品 / 服务明细
商品名称
规格型号
单位
数量
单价
不含税金额
税率
税额
{{ $('GoogleSheets').first().json["商品名称"] || "" }}
{{ $('GoogleSheets').first().json["规格型号"] || "" }}
{{ $('GoogleSheets').first().json["单位"] || "" }}
{{ $('GoogleSheets').first().json["数量"] || "" }}
¥{{ parseFloat($('GoogleSheets').first().json["单价"] || 0).toFixed(2) }}
¥{{ parseFloat($('GoogleSheets').first().json["不含税金额"] || 0).toFixed(2) }}
{{ $('GoogleSheets').first().json["税率显示"] || (parseFloat($('GoogleSheets').first().json["税率"] || 0)*100).toFixed(0) + "%" }}
¥{{ parseFloat($('GoogleSheets').first().json["税额"] || 0).toFixed(2) }}
合计不含税金额:
¥{{ parseFloat($('GoogleSheets').first().json["合计不含税金额"] || 0).toFixed(2) }}
合计税额:
¥{{ parseFloat($('GoogleSheets').first().json["合计税额"] || 0).toFixed(2) }}
合计价税合计金额:
¥{{ parseFloat($('GoogleSheets').first().json["合计价税合计金额"] || 0).toFixed(2) }}
开票人:{{ $('GoogleSheets').first().json["开票人"] || "" }}
```
点开看一下,如果不飙红并且能看到数据,说明是正常的

点击执行,输出结果是正常的

邮件也收到了

打开邮件可以看到内容:

以上就是发票机器人的完整流程。
如果你想偷懒,可以直接导入我的 json 文件,再参考攻略,配置自己的节点就可以了
```
{
"name": "analyze image and send email",
"nodes": [
{
"parameters": {
"jsCode": "// n8n Code 节点 - 发票数据解析\n// 获取输入数据(处理可能的字符串格式)\nconst inputData = $input.first().json.choices[0].message.content;\n\n// 如果输入是字符串,先解析为 JSON\nlet invoiceData;\nif (typeof inputData === 'string') {\n // 移除可能的 markdown 代码块标记\n const cleanData = inputData.replace(/^```json\\s*/, '').replace(/\\s*```$/, '').trim();\n invoiceData = JSON.parse(cleanData);\n} else {\n invoiceData = inputData;\n}\n\n// 提取发票数据\nconst invoice = invoiceData.invoice;\n\n// 返回扁平化的 JSON 数据\nreturn [{\n json: {\n title: invoice.title,\n invoiceNumber: invoice.number,\n issueDate: invoice.issue_date,\n currency: invoice.currency,\n issuer: invoice.issuer,\n buyerName: invoice.buyer.name,\n buyerTaxId: invoice.buyer.tax_id,\n buyerNote: invoice.buyer.note,\n sellerName: invoice.seller.name,\n sellerTaxId: invoice.seller.tax_id,\n itemName: invoice.items[0].name,\n itemSpec: invoice.items[0].spec,\n itemUnit: invoice.items[0].unit,\n quantity: invoice.items[0].quantity,\n unitPrice: invoice.items[0].unit_price,\n amountWithoutTax: invoice.items[0].amount_without_tax,\n taxRate: invoice.items[0].tax_rate,\n taxRateDisplay: invoice.items[0].tax_rate_display,\n taxAmount: invoice.items[0].tax_amount,\n subtotal: invoice.totals.amount_without_tax,\n totalTax: invoice.totals.tax_total,\n grandTotal: invoice.totals.amount_with_tax\n }\n}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
0,
200
],
"id": "70bef82b-f44f-4389-adc2-d1e41a1ef12a",
"name": "Code"
},
{
"parameters": {
"operation": "append",
"documentId": {
"__rl": true,
"value": "1M6GJAC6j3fvzZd2EImGSyugzLRKwa_Ok5ODnL6q4PWo",
"mode": "list",
"cachedResultName": "发票",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1M6GJAC6j3fvzZd2EImGSyugzLRKwa_Ok5ODnL6q4PWo/edit?usp=drivesdk"
},
"sheetName": {
"__rl": true,
"value": "gid=0",
"mode": "list",
"cachedResultName": "Sheet1",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1M6GJAC6j3fvzZd2EImGSyugzLRKwa_Ok5ODnL6q4PWo/edit#gid=0"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"发票标题": "={{ $json.title }}",
"发票号码": "={{ $json.invoiceNumber }}",
"开票日期": "={{ $json.issueDate }}",
"购方名称": "={{ $json.buyerName }}",
"购方税号": "={{ $json.buyerTaxId }}",
"购方备注": "={{ $json.buyerNote }}",
"销方名称": "={{ $json.sellerName }}",
"商品名称": "={{ $json.itemName }}",
"销方税号": "={{ $json.sellerTaxId }}",
"规格型号": "={{ $json.itemSpec }}",
"单位": "={{ $json.itemUnit }}",
"数量": "={{ $json.quantity }}",
"单价": "={{ $json.unitPrice }}",
"不含税金额": "={{ $json.amountWithoutTax }}",
"税率": "={{ $json.taxRate }}",
"税率显示": "={{ $json.taxRateDisplay }}",
"税额": "={{ $json.taxAmount }}",
"合计不含税金额": "={{ $json.subtotal }}",
"合计税额": "={{ $json.totalTax }}",
"合计价税合计金额": "={{ $json.grandTotal }}",
"开票人": "={{ $json.issuer }}"
},
"matchingColumns": [],
"schema": [
{
"id": "发票标题",
"displayName": "发票标题",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "发票号码",
"displayName": "发票号码",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "开票日期",
"displayName": "开票日期",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "购方名称",
"displayName": "购方名称",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "购方税号",
"displayName": "购方税号",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "购方备注",
"displayName": "购方备注",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "销方名称",
"displayName": "销方名称",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "销方税号",
"displayName": "销方税号",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "商品名称",
"displayName": "商品名称",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "规格型号",
"displayName": "规格型号",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "单位",
"displayName": "单位",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "数量",
"displayName": "数量",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "单价",
"displayName": "单价",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "不含税金额",
"displayName": "不含税金额",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "税率",
"displayName": "税率",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "税率显示",
"displayName": "税率显示",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "税额",
"displayName": "税额",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "合计不含税金额",
"displayName": "合计不含税金额",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "合计税额",
"displayName": "合计税额",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "合计价税合计金额",
"displayName": "合计价税合计金额",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "开票人",
"displayName": "开票人",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.6,
"position": [
260,
80
],
"id": "9a9b3088-7722-4dd5-b2b7-28726fd64f8f",
"name": "Google Sheets",
"credentials": {
"googleSheetsOAuth2Api": {
"id": "jflKNS6HMBOKZok2",
"name": "Google Sheets account"
}
}
},
{
"parameters": {
"jsCode": "const raw = $('When chat message received').first().json.chatInput|| \"\";\n\n// 匹配第一个邮箱格式\nconst match = raw.match(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/);\n\nreturn [\n {\n json: {\n email: match ? match[0] : null\n }\n }\n];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
420,
-80
],
"id": "5e71f0be-bebb-42ac-9d64-413d98b4e5db",
"name": "Code1"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "a44e6c17-4473-4dfe-bab9-5c98caa8fa31",
"leftValue": "={{ $json.email }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
640,
-80
],
"id": "e50264b2-51e1-4c2a-bb0d-66447b6f3b0d",
"name": "If"
},
{
"parameters": {
"sendTo": "={{ $json.email }}",
"subject": "发票",
"message": "=\n \n \n \n {{ $('Google Sheets').item.json[\"发票标题\"] || \"发票\" }}\n \n \n 发票号码:{{ $('Google Sheets').item.json[\"发票号码\"] || \"\" }} \n 开票日期:{{ $('Google Sheets').item.json[\"开票日期\"] || \"\" }} \n \n \n \n\n \n \n \n \n 购方信息\n 名称:{{ $('Google Sheets').item.json[\"购方名称\"] || \"\" }}\n 税号:{{ $('Google Sheets').item.json[\"购方税号\"] || \"\" }}\n 备注:{{ $('Google Sheets').item.json[\"购方备注\"] || \"\" }}\n \n \n 销方信息\n 名称:{{ $('Google Sheets').item.json[\"销方名称\"] || \"\" }}\n 税号:{{ $('Google Sheets').item.json[\"销方税号\"] || \"\" }}\n \n \n \n\n \n \n 商品 / 服务明细\n \n \n \n 商品名称\n 规格型号\n 单位\n 数量\n 单价\n 不含税金额\n 税率\n 税额\n \n \n \n \n {{ $('Google Sheets').item.json[\"商品名称\"] || \"\" }}\n {{ $('Google Sheets').item.json[\"规格型号\"] || \"\" }}\n {{ $('Google Sheets').item.json[\"单位\"] || \"\" }}\n {{ $('Google Sheets').item.json[\"数量\"] ?? \"\" }}\n {{ Number($('Google Sheets').item.json[\"单价\"] ?? 0).toFixed(6) }}\n {{ Number($('Google Sheets').item.json[\"不含税金额\"] ?? 0).toFixed(2) }}\n \n {{ $('Google Sheets').item.json[\"税率显示\"] || (Number($('Google Sheets').item.json[\"税率\"] ?? 0)*100).toFixed(0) + \"%\" }}\n \n {{ Number($('Google Sheets').item.json[\"税额\"] ?? 0).toFixed(2) }}\n \n \n \n \n\n \n \n \n \n 合计不含税金额:\n \n {{ Number($('Google Sheets').item.json[\"合计不含税金额\"] ?? 0).toFixed(2) }}\n \n \n \n 合计税额:\n \n {{ Number($('Google Sheets').item.json[\"合计税额\"] ?? 0).toFixed(2) }}\n \n \n \n 合计价税合计金额:\n \n {{ Number($('Google Sheets').item.json[\"合计价税合计金额\"] ?? 0).toFixed(2) }}\n \n \n \n \n\n \n \n 开票人:{{ $('Google Sheets').item.json[\"开票人\"] || \"\" }}\n \n\n",
"options": {}
},
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
1060,
-60
],
"id": "16486451-dabf-48d7-98a9-77851add9d47",
"name": "Gmail",
"webhookId": "7f924497-ae8b-4b4e-8cad-3b4cd7a162d9",
"credentials": {
"gmailOAuth2": {
"id": "lLR0rjkd7MVl0WuY",
"name": "Gmail account"
}
}
},
{
"parameters": {
"options": {
"allowFileUploads": true
}
},
"type": "@n8n/n8n-nodes-langchain.chatTrigger",
"typeVersion": 1.1,
"position": [
-760,
200
],
"id": "7e8689a3-250d-466a-a4b1-1e42a8f014d4",
"name": "When chat message received",
"webhookId": "d7c99574-86d3-42f4-adf2-69f9fc1f7d3d"
},
{
"parameters": {
"method": "POST",
"url": "https://api.imgbb.com/1/upload?expiration=6000&key=80ddf220f655b5887b8a5eeee2a3652e",
"sendBody": true,
"contentType": "multipart-form-data",
"bodyParameters": {
"parameters": [
{
"parameterType": "formBinaryData",
"name": "image",
"inputDataFieldName": "data0"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-560,
200
],
"id": "0849a0c5-dafc-4af7-ac7d-8b463df5abb9",
"name": "IMGBB"
},
{
"parameters": {
"method": "POST",
"url": "https://api.gpt.ge/v1/chat/completions",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"model\": \"gpt-4o\",\n \"messages\": [\n {\n \"role\": \"user\",\n \"content\": [\n {\n \"type\": \"text\",\n \"text\": \"## 角色\\n你是一个专业的\\\"发票信息抽取器\\\"。输入是一段发票文字(可能来自 OCR、邮件正文或聊天粘贴),输出是严格有效的 JSON,适合直接写入数据库/Google Sheets。\\n## 任务\\n从给定的发票文本中识别并抽取字段,返回单个 JSON 对象,放在一个标记代码块里(json ... )。不要输出任何解释、注释或多余字符。\\n## 输出要求\\n仅输出一个 JSON 代码块,不得包含额外文字。\\n不存在或不确定的值一律填 null。\\n日期统一为 YYYY-MM-DD(ISO 8601);\\n金额/数量等数值字段用 数字类型(而非字符串),保留精度但不要添加货币符号或千分位。\\n税率使用小数(例如 1% → 0.01),并同时提供显示字段(例如 \\\"1%\\\")。\\nitems 数组必须存在;若无行项目,输出空数组 []。\\n## 字段定义(Schema)\\n{\\n \\\"invoice\\\": {\\n \\\"title\\\": \\\"string|null\\\",\\n \\\"number\\\": \\\"string|null\\\",\\n \\\"issue_date\\\": \\\"YYYY-MM-DD|null\\\",\\n \\\"currency\\\": \\\"string|null\\\",\\n \\\"buyer\\\": {\\n \\\"name\\\": \\\"string|null\\\",\\n \\\"tax_id\\\": \\\"string|null\\\",\\n \\\"note\\\": \\\"string|null\\\"\\n },\\n \\\"seller\\\": {\\n \\\"name\\\": \\\"string|null\\\",\\n \\\"tax_id\\\": \\\"string|null\\\"\\n },\\n \\\"items\\\": [\\n {\\n \\\"name\\\": \\\"string|null\\\",\\n \\\"spec\\\": \\\"string|null\\\",\\n \\\"unit\\\": \\\"string|null\\\",\\n \\\"quantity\\\": \\\"number|null\\\",\\n \\\"unit_price\\\": \\\"number|null\\\",\\n \\\"amount_without_tax\\\": \\\"number|null\\\",\\n \\\"tax_rate\\\": \\\"number|null\\\",\\n \\\"tax_rate_display\\\": \\\"string|null\\\",\\n \\\"tax_amount\\\": \\\"number|null\\\"\\n }\\n ],\\n \\\"totals\\\": {\\n \\\"amount_without_tax\\\": \\\"number|null\\\",\\n \\\"tax_total\\\": \\\"number|null\\\",\\n \\\"amount_with_tax\\\": \\\"number|null\\\"\\n },\\n \\\"issuer\\\": \\\"string|null\\\"\\n }\\n}\"\n },\n {\n \"type\": \"image_url\",\n \"image_url\": {\n \"url\": \"{{ $json.data.url }}\"\n }\n }\n ]\n }\n ]\n} ",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-240,
200
],
"id": "24b25ed1-18d8-4c8a-9d2e-d903168e9b8e",
"name": "识别图片",
"retryOnFail": true,
"credentials": {
"httpHeaderAuth": {
"id": "BKtGro8HEgz5LcZM",
"name": "V3 Header Auth account"
}
}
}
],
"pinData": {},
"connections": {
"Code": {
"main": [
[
{
"node": "Google Sheets",
"type": "main",
"index": 0
}
]
]
},
"Google Sheets": {
"main": [
[
{
"node": "Code1",
"type": "main",
"index": 0
}
]
]
},
"Code1": {
"main": [
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
},
"If": {
"main": [
[
{
"node": "Gmail",
"type": "main",
"index": 0
}
]
]
},
"When chat message received": {
"main": [
[
{
"node": "IMGBB",
"type": "main",
"index": 0
}
]
]
},
"IMGBB": {
"main": [
[
{
"node": "识别图片",
"type": "main",
"index": 0
}
]
]
},
"识别图片": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "fb865209-ec18-41a6-b252-def147580997",
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "3cb07a731a78af260d8c81716bfc0e842ef01e898e945b902a3871e6a1cd0d48"
},
"id": "OWymQVChmL3XifYL",
"tags": []
}
```
评论
0暂无评论