Skip to content

Latest commit

 

History

History
185 lines (128 loc) · 13.6 KB

File metadata and controls

185 lines (128 loc) · 13.6 KB

Mail2Cashew-TPS (Transaction Processing Service)

A Google Apps Script that reads your bank transaction emails and SMS, extracts the details, and creates one-tap Cashew links to add them to your budget tracker. No manual data entry needed.

The script is highly configurable, supports automated email labeling, and integrates error reporting. It generates deep links for the Cashew app on both web and mobile, so you can add transactions to your accounts with a single tap.

How It Works

  1. You make a transaction. Your bank sends a transaction email or SMS.

  2. Gmail labels it automatically. A Gmail filter tags the email with a label like Txs/💳 (for bank emails) or Txs/💬 (for SMS forwarded as email). For SMS, the SmsForwarder app on your phone forwards the SMS to Gmail first.

  3. TPS runs on a time-driven trigger (e.g., every 15 minutes) or you trigger it manually by visiting the deployed web app URL.

  4. Regex rules parse the amount, date, account, merchant, and category from each message.

  5. You get a summary email with every transaction laid out in a table. Each row is color-coded:

    • Orange = expense (debit)
    • Green = income (credit, refund, salary, cashback)
    • Red = duplicate (already exists in your sheet, excluded from batch URL)
    • Blue = transfer (in the dedicated Transfers section)

    The email includes two types of links. PC links open in a browser and take you to the Cashew web app where you can review and confirm. Mobile links open the Cashew mobile app directly (requires the app to be installed on your phone). Both link types have an Approve button (adds all non-duplicate transactions in one go) and an Edit button (opens the edit view so you can tweak before saving). Budget tags like [Monthly Budget] appear next to the category when auto-assigned.

    Success email showing expenses, income, duplicates, transfers, budget tags, and warnings

  6. Transfers get their own section with per-row PC and Mobile approve links. Self-linked transfers, ATM withdrawals, and NEFT/UPI transfers are detected automatically. Transfers to unknown external accounts (where the destination account is not in your accountKeywordMap) appear in the main Transactions table as regular debits instead. Real success email showing the Transfers section with per-row PC and Mobile approve links

  7. Errors notify you immediately when a message fails to parse, so you can fix the regex. The email gets labeled Txs/🛠️ (To Fix) and will be excluded from future runs until the rule is updated. See Reprocessing failed emails for steps to retry. Error notification email

  8. Everything is logged in a Google Sheet for analysis, reprocessing, and audit. Each row includes a single-transaction URL so you can approve individual transactions even outside the batch email. The sheet also holds your test cases.

    Download sample spreadsheet Google Sheet with transaction data

Features

  • Automated processing of bank emails and SMS (forwarded via SmsForwarder)
  • Transfer support for account-to-account, NEFT, and UPI transfers with separate Cashew transfer links
  • Regex-based parsing with per-bank/per-message-type rules for date, amount, account, merchant, category
  • Smart categorization using a keyword hierarchy (category > subcategory > keywords) with budget assignment
  • Title normalization to map noisy raw titles to clean, stable names in Cashew (see below)
  • Budget auto-assignment from categories/subcategories to Cashew budgets (see below)
  • HTML body parsing for emails where the plain text is truncated or missing. Some emails render visible text using HTML/CSS (e.g., styled tables or divs) but their plain text version is empty or has only a short fallback like "View in browser". For these, add the Rule ID to HTML_BODY_RULE_IDS and TPS will parse the full HTML instead.
  • Duplicate detection against existing sheet rows, with O(n) performance
  • Gmail labeling per-email (not per-thread) so partially failed threads can be reprocessed. If one email in a thread succeeds and another fails, only the failed one is retried on the next run. See why this matters.
  • Sanity test framework to validate your regex rules against expected outputs
  • Configurable everything -- processing filters, error handling, test modes, rerun behavior

Title Normalization

Bank transaction descriptions are often messy. You might see PYU*Instamart Grocery, AMAZON PAY IN GROCERY, or WALMART GROCERY for what is really just a grocery purchase. Title normalization maps these raw titles to a clean, consistent name in Cashew.

You configure this in titleMappingConfig in your userConfig. There are two types of mappings:

  • Exact mappings: Raw title contains one of the listed strings, so it maps directly. For example, ["WALMART GROCERY", "AMAZON FRESH"] both map to "Groceries".
  • Contextual mappings: When the exact title is too generic (like "PURCHASE"), TPS looks at the notes field for additional context. For example, if notes contain "WHOLE FOODS", the title becomes "Groceries" instead of the generic "Misc Purchase".

You will want to come back and update these mappings as you notice new raw titles appearing in your Cashew transactions that could use a cleaner name.

Budget Auto-Assignment

If you use Cashew's "Added Only" budgets to track spending limits (like a "Monthly Bills" or "Consumables" budget), TPS can automatically assign the right budget to each transaction based on its category or subcategory.

Configure this in categoryToBudgetMap. The lookup checks subcategory first (more specific), then category (broader). Budget names must exactly match the budget names in your Cashew app. Transactions without a matching budget are left unassigned.

Quick Start

  1. Create a Google Apps Script project
  2. Upload the 5 script files in order (constants, userConfig, main, utils, test)
  3. Add the Moment.js library and enable the Gmail API
  4. Copy 2-sampleUserConfig.gs, customize the regex rules for your banks
  5. Store your credentials via storeSecrets() and delete them from the file
  6. Set up a Google Sheet and configure a time-driven trigger

Full step-by-step instructions: Setup Guide

Typical Workflow

Once setup is done, this is the day-to-day flow:

  1. You make a transaction (swipe card, UPI payment, online purchase, etc.).
  2. Your bank sends an email or SMS.
  3. If it's an SMS, SmsForwarder on your phone forwards it to Gmail as an email.
  4. Gmail's filter auto-labels the email (e.g., Txs/💳 for bank emails, Txs/💬 for SMS).
  5. TPS runs at the next scheduled trigger (or you visit the /exec URL to run it now).
  6. TPS processes all unread, labeled emails and sends you a summary.
  7. Success? Open the Approve link from the email (PC or Mobile) to add transactions to Cashew. Done.
  8. Error? The failing email gets labeled Txs/🛠️ and you receive an error email with the message body and what went wrong. Fix the regex in your userConfig, then reprocess using test.gs.
  9. Duplicate? The row shows up in red in the summary but is excluded from the Approve URL. If you still want it, use the single-transaction URL from the Google Sheet row.

Gmail Labels Reference

Label Applied by Meaning
Txs/💳 Gmail filter Bank transaction email, waiting to be processed
Txs/💬 Gmail filter Single SMS forwarded as email via SmsForwarder
Txs/🛜 Gmail filter Offline SMS batch (legacy, used with Automate app)
Txs/🧪 You (manual) Test case email for sanity tests
Txs/❌ You (manual) Ignored email, skipped by TPS even if other labels match
Txs/✅ TPS Successfully processed, will not be picked up again
Txs/🛠️ TPS Failed to process, needs a regex fix. Excluded from future runs until fixed and reprocessed.

SMS Support

TPS handles SMS through SmsForwarder, an Android app that forwards bank SMS and app notifications to your Gmail as emails. TPS then processes them the same way it processes regular bank emails.

This gives you coverage for transaction types that banks only report via SMS (UPI, debit card POS, instant transfers) without any changes to TPS's email-based pipeline.

Full setup walkthrough with rule examples: SMS Setup Guide

Deployment and Triggers

  1. In Apps Script, go to Deploy > New Deployment, select Web App, set access to "Anyone with the link", and save the URL.
  2. The /exec endpoint runs the last deployed version. The /dev endpoint runs the latest saved code without redeploying (useful for testing).
  3. For automated runs, go to Triggers > Add Trigger and set up a time-driven trigger (e.g., every 15 minutes or hourly).

Full deployment and dev guide: Development Guide

Ongoing Configuration

Once TPS is set up and running, you will regularly need to add new rules or tweak existing ones as your banks change formats or you start using new payment methods. Here are the most common tasks:

How do I add a new bank account?

  1. Add the account key and keywords to baseAccountIdsMap (e.g., "NEWBANK_SAVINGS": ["NewBank"])
  2. Add the display name to accountIdsToDisplayNameMap (e.g., "NEWBANK_SAVINGS": "NewBank")
  3. Add secret identifiers to mySecrets (e.g., ACCOUNT_ID_NEWBANK_SAVINGS: ["XX1234"]) and run storeSecrets(mySecrets) once
  4. Delete the actual values from the file after storing

How do I add a new email transaction rule?

  1. Add the email subject to emailSubjectToRuleIdMap with a unique Rule ID
  2. Add the Rule ID to emailRuleMap with regex patterns for each field (amount, date, account, merchant, etc.)
  3. If the email has truncated plain text, add the Rule ID to HTML_BODY_RULE_IDS
  4. Create a Gmail filter for the subject to apply the Txs/💳 label
  5. Test with a real email using getTestThreadsOrQuery() in test.gs

How do I add a new SMS rule?

  1. Add an identification regex to smsReferencePatterns (matches the SMS body to determine which rule applies)
  2. Add extraction regex to smsRuleMap (pulls out amount, account, merchant, etc.)
  3. If this SMS is a duplicate of an email you already process, add the pattern to the DUPLICATE section in smsReferencePatterns instead
  4. If needed, add a SmsForwarder rule on your phone for the new bank's sender ID. See SMS Setup Guide.

How do I update category keywords?

Edit categorySubcategoryKeywordMap in your userConfig. Add new merchant keywords to the relevant subcategory. Order matters -- first match wins, so put more specific keywords in earlier categories.

How do I set up budget auto-assignment for a category?

Add an entry to categoryToBudgetMap. The key is the category or subcategory name, the value is the exact budget name in Cashew. Subcategory-level entries take priority over category-level ones.

How do I add a title normalization mapping?

Edit titleMappingConfig. For a straightforward raw-title-to-clean-title mapping, add to exactTitleMappings. If the raw title is too generic and you need to check the notes field for context, add to contextualMappings.

How do I reprocess failed emails?

  1. Fix the regex rule in your userConfig
  2. In 5-test.gs, set the failing email's thread ID in getTestThreadsOrQuery(): return ['thread_id'];
  3. Set DEV_CONFIG.RERUN_READ_MAILS = true and DEV_CONFIG.MARK_AS_PROCESSED = false
  4. Run via the /dev endpoint or testDoGet()
  5. If it passes, remove the Txs/🛠️ label from the email and let TPS process it normally on the next trigger

Project Structure

File Purpose
1-constants.gs Config objects, enums, labels, error types
2-sampleUserConfig.gs Template with annotated regex rules, categories, accounts (customize this)
3-main.gs Entry point -- email loop, transaction extraction, sheet append
4-utils.gs All utility functions: parsing, email generation, sheet ops
5-test.gs Dev config, test helpers, sanity test framework
resources/ Sample sheet, screenshots, setup guides, changelog

What's New in v2.0

Transfer transaction support, O(n) duplicate detection, HTML body parsing, budget assignment, title normalization, and a redesigned success email with separate normal and transfer sections. See the full Changelog.

Reporting Dashboard

Once your transactions are in Cashew, Cashew-Reports turns them into a visual dashboard - numerous widgets covering burn rate, savings, category breakdowns, spending trends, and more. It reads the same Cashew Outbox CSV and runs as a separate GAS Web App.

If you use both repos, keep the category and subcategory names in sync: TPS's categorySubcategoryKeywordMap should match the CONFIG section in Cashew-Reports' Code.gs.

Roadmap

  • Notification scanning for payment apps (Google Pay, PhonePe) via SmsForwarder APP rules
  • Bulk SMS sheet import mode for processing offline SMS batches