Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6d88f6abe | ||
|
|
0449e7bdaa | ||
|
|
10bc441e1e | ||
|
|
6f3bf1f6a4 | ||
|
|
09f14ec44c |
9
bank.go
9
bank.go
@@ -3,13 +3,16 @@ package main
|
|||||||
type Bank int
|
type Bank int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Chase Bank = iota + 1
|
Chase Bank = iota + 1
|
||||||
Citi Bank = iota + 1
|
Citi Bank = iota + 1
|
||||||
UCCU Bank = iota + 1
|
UCCU Bank = iota + 1
|
||||||
|
BankOfAmerica Bank = iota + 1
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b Bank) String() string {
|
func (b Bank) String() string {
|
||||||
switch b {
|
switch b {
|
||||||
|
case BankOfAmerica:
|
||||||
|
return "BankOfAmerica"
|
||||||
case Chase:
|
case Chase:
|
||||||
return "Chase"
|
return "Chase"
|
||||||
case Citi:
|
case Citi:
|
||||||
|
|||||||
13
config.go
13
config.go
@@ -7,6 +7,7 @@ import (
|
|||||||
"local/args"
|
"local/args"
|
||||||
"local/oauth2"
|
"local/oauth2"
|
||||||
"local/storage"
|
"local/storage"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -44,7 +45,7 @@ func NewConfig() Config {
|
|||||||
as := args.NewArgSet()
|
as := args.NewArgSet()
|
||||||
|
|
||||||
as.Append(args.STRING, "emailuser", "email username", "breellocaldev@gmail.com")
|
as.Append(args.STRING, "emailuser", "email username", "breellocaldev@gmail.com")
|
||||||
as.Append(args.STRING, "emailpass", "email password", "ML3WQRFSqe9rQ8qNkm")
|
as.Append(args.STRING, "emailpass", "email password", "diblloewfncwssof")
|
||||||
as.Append(args.STRING, "emailimap", "email imap", "imap.gmail.com:993")
|
as.Append(args.STRING, "emailimap", "email imap", "imap.gmail.com:993")
|
||||||
|
|
||||||
as.Append(args.STRING, "uploader", "todo, ledger", "todo")
|
as.Append(args.STRING, "uploader", "todo, ledger", "todo")
|
||||||
@@ -55,7 +56,7 @@ func NewConfig() Config {
|
|||||||
as.Append(args.STRING, "todolist", "todo list", "")
|
as.Append(args.STRING, "todolist", "todo list", "")
|
||||||
as.Append(args.STRING, "todotag", "todo tag", "expense")
|
as.Append(args.STRING, "todotag", "todo tag", "expense")
|
||||||
|
|
||||||
as.Append(args.STRING, "banks", "uccu,citi,chase", "uccu,citi,chase")
|
as.Append(args.STRING, "banks", "uccu,citi,chase,bankofamerica", "uccu,citi,chase,bankofamerica")
|
||||||
as.Append(args.STRING, "accounts", "regex to include filter accounts", ".*")
|
as.Append(args.STRING, "accounts", "regex to include filter accounts", ".*")
|
||||||
as.Append(args.STRING, "not-accounts", "regex to exclude filter accounts", "zzzzzz")
|
as.Append(args.STRING, "not-accounts", "regex to exclude filter accounts", "zzzzzz")
|
||||||
|
|
||||||
@@ -91,11 +92,13 @@ func NewConfig() Config {
|
|||||||
Storage: storage,
|
Storage: storage,
|
||||||
Uploader: ul,
|
Uploader: ul,
|
||||||
Banks: map[Bank]bool{
|
Banks: map[Bank]bool{
|
||||||
Chase: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(Chase.String())),
|
BankOfAmerica: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(BankOfAmerica.String())),
|
||||||
Citi: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(Citi.String())),
|
Chase: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(Chase.String())),
|
||||||
UCCU: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(UCCU.String())),
|
Citi: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(Citi.String())),
|
||||||
|
UCCU: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(UCCU.String())),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
log.Printf("config: %+v", config)
|
||||||
|
|
||||||
if config.Uploader == UploaderTodo {
|
if config.Uploader == UploaderTodo {
|
||||||
token := as.GetString("todotoken")
|
token := as.GetString("todotoken")
|
||||||
|
|||||||
102
scrape.go
102
scrape.go
@@ -15,6 +15,7 @@ type scraper interface {
|
|||||||
scrape(*mail.Message) ([]*Transaction, error)
|
scrape(*mail.Message) ([]*Transaction, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type bankOfAmericaScraper struct{}
|
||||||
type chaseScraper struct{}
|
type chaseScraper struct{}
|
||||||
type citiScraper struct{}
|
type citiScraper struct{}
|
||||||
type uccuScraper struct{}
|
type uccuScraper struct{}
|
||||||
@@ -29,13 +30,16 @@ func Scrape(m *mail.Message, banks map[Bank]bool) ([]*Transaction, error) {
|
|||||||
|
|
||||||
func buildScraper(m *mail.Message, banks map[Bank]bool) (scraper, error) {
|
func buildScraper(m *mail.Message, banks map[Bank]bool) (scraper, error) {
|
||||||
subject := fmt.Sprint(m.Header["Subject"])
|
subject := fmt.Sprint(m.Header["Subject"])
|
||||||
if !containsAny(subject, "transaction", "report", "Transaction") {
|
if !containsAny(subject, "transaction", "report", "Transaction", "payment") {
|
||||||
return nil, errors.New("cannot build scraper for subject " + subject)
|
return nil, errors.New("cannot build scraper for subject " + subject)
|
||||||
}
|
}
|
||||||
from := fmt.Sprint(m.Header["From"])
|
from := fmt.Sprint(m.Header["From"])
|
||||||
if strings.Contains(from, "Chase") && banks[Chase] {
|
if strings.Contains(from, "Chase") && banks[Chase] {
|
||||||
return newChaseScraper(), nil
|
return newChaseScraper(), nil
|
||||||
}
|
}
|
||||||
|
if strings.Contains(from, "Bank of America") && banks[BankOfAmerica] {
|
||||||
|
return newBankOfAmericaScraper(), nil
|
||||||
|
}
|
||||||
if strings.Contains(from, "Citi") && banks[Citi] {
|
if strings.Contains(from, "Citi") && banks[Citi] {
|
||||||
return newCitiScraper(), nil
|
return newCitiScraper(), nil
|
||||||
}
|
}
|
||||||
@@ -45,6 +49,10 @@ func buildScraper(m *mail.Message, banks map[Bank]bool) (scraper, error) {
|
|||||||
return nil, errors.New("unknown sender: " + from)
|
return nil, errors.New("unknown sender: " + from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newBankOfAmericaScraper() scraper {
|
||||||
|
return &bankOfAmericaScraper{}
|
||||||
|
}
|
||||||
|
|
||||||
func newChaseScraper() scraper {
|
func newChaseScraper() scraper {
|
||||||
return &chaseScraper{}
|
return &chaseScraper{}
|
||||||
}
|
}
|
||||||
@@ -75,6 +83,38 @@ func (c *chaseScraper) scrape(m *mail.Message) ([]*Transaction, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *chaseScraper) scrape2021(m *mail.Message) ([]*Transaction, error) {
|
func (c *chaseScraper) scrape2021(m *mail.Message) ([]*Transaction, error) {
|
||||||
|
if t, err := c.scrape2021Payment(m); err == nil {
|
||||||
|
return t, err
|
||||||
|
}
|
||||||
|
return c.scrape2021Charge(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *chaseScraper) scrape2021Payment(m *mail.Message) ([]*Transaction, error) {
|
||||||
|
re := regexp.MustCompile(`^We've received your .* payment$`)
|
||||||
|
if !re.Match([]byte(m.Header["Subject"][0])) {
|
||||||
|
return nil, errors.New("no match subject search")
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := ioutil.ReadAll(m.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
re = regexp.MustCompile(`\$[0-9]+\.[0-9]{2}`)
|
||||||
|
amount := "-" + strings.TrimLeft(string(re.Find(b)), "$")
|
||||||
|
amount = strings.TrimLeft(string(re.Find(b)), "$")
|
||||||
|
|
||||||
|
vendor := "Payment"
|
||||||
|
|
||||||
|
re = regexp.MustCompile(`\(\.\.\.[0-9]{4}\)`)
|
||||||
|
match := re.Find(b)
|
||||||
|
re = regexp.MustCompile(`[0-9]{4}`)
|
||||||
|
account := string(re.Find(match))
|
||||||
|
|
||||||
|
return []*Transaction{NewTransaction(account, amount, vendor, fmt.Sprint(m.Header["Date"]), Chase)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *chaseScraper) scrape2021Charge(m *mail.Message) ([]*Transaction, error) {
|
||||||
re := regexp.MustCompile(`^Your \$(?P<amount>[0-9\.]*) transaction with (?P<vendor>.*)$`)
|
re := regexp.MustCompile(`^Your \$(?P<amount>[0-9\.]*) transaction with (?P<vendor>.*)$`)
|
||||||
matches := re.FindSubmatch([]byte(m.Header["Subject"][0]))
|
matches := re.FindSubmatch([]byte(m.Header["Subject"][0]))
|
||||||
if len(matches) < 1 {
|
if len(matches) < 1 {
|
||||||
@@ -206,3 +246,63 @@ func (c *uccuScraper) scrape(m *mail.Message) ([]*Transaction, error) {
|
|||||||
transaction := NewTransaction(UCCU.String(), fmt.Sprintf("%.2f", f), "?", fmt.Sprint(m.Header["Date"]), UCCU)
|
transaction := NewTransaction(UCCU.String(), fmt.Sprintf("%.2f", f), "?", fmt.Sprint(m.Header["Date"]), UCCU)
|
||||||
return []*Transaction{transaction}, nil
|
return []*Transaction{transaction}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *bankOfAmericaScraper) scrape(m *mail.Message) ([]*Transaction, error) {
|
||||||
|
subject := fmt.Sprint(m.Header["Subject"])
|
||||||
|
if strings.Contains(subject, "Credit card transaction") {
|
||||||
|
return c.scrapeCharge(m)
|
||||||
|
}
|
||||||
|
if strings.Contains(subject, "Credit Card Payment") {
|
||||||
|
return c.scrapePayment(m)
|
||||||
|
}
|
||||||
|
return nil, errors.New("not impl")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *bankOfAmericaScraper) scrapeCharge(m *mail.Message) ([]*Transaction, error) {
|
||||||
|
b, err := ioutil.ReadAll(m.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
amount := c.findFloatAfter(b, "Amount: $")
|
||||||
|
acc := string(c.findLineAfter(b, "Where: "))
|
||||||
|
|
||||||
|
if amount == "" || acc == "" {
|
||||||
|
return nil, errors.New("no amount/account found")
|
||||||
|
}
|
||||||
|
transaction := NewTransaction(BankOfAmerica.String(), amount, acc, fmt.Sprint(m.Header["Date"]), BankOfAmerica)
|
||||||
|
return []*Transaction{transaction}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *bankOfAmericaScraper) scrapePayment(m *mail.Message) ([]*Transaction, error) {
|
||||||
|
b, err := ioutil.ReadAll(m.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
amount := "-" + c.findFloatAfter(b, "Payment: $")
|
||||||
|
acc := "Payment"
|
||||||
|
if amount == "" || acc == "" {
|
||||||
|
return nil, errors.New("no amount/account found")
|
||||||
|
}
|
||||||
|
transaction := NewTransaction(BankOfAmerica.String(), amount, acc, fmt.Sprint(m.Header["Date"]), BankOfAmerica)
|
||||||
|
return []*Transaction{transaction}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *bankOfAmericaScraper) findFloatAfter(b []byte, prefix string) string {
|
||||||
|
amount := string(c.findLineAfter(b, prefix))
|
||||||
|
words := strings.Split(amount, " ")
|
||||||
|
lastword := words[len(words)-1]
|
||||||
|
escapedfloat := strings.TrimPrefix(lastword, "$")
|
||||||
|
fixEscape := strings.ReplaceAll(escapedfloat, "=2E", ".")
|
||||||
|
amount = fixEscape
|
||||||
|
return amount
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *bankOfAmericaScraper) findLineAfter(b []byte, prefix string) []byte {
|
||||||
|
for _, line := range bytes.Split(b, []byte("\n")) {
|
||||||
|
if bytes.HasPrefix(line, []byte(prefix)) {
|
||||||
|
return bytes.TrimSpace(bytes.TrimPrefix(line, []byte(prefix)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
105
scrape_test.go
105
scrape_test.go
@@ -7,6 +7,41 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestScrapeChase2021Payment(t *testing.T) {
|
||||||
|
b, err := ioutil.ReadFile("./testdata/chase.2021.payment.txt")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
message := &mail.Message{
|
||||||
|
Header: map[string][]string{
|
||||||
|
"Subject": []string{"We've received your AARP from Chase payment"},
|
||||||
|
},
|
||||||
|
Body: bytes.NewReader(b),
|
||||||
|
}
|
||||||
|
|
||||||
|
chase := &chaseScraper{}
|
||||||
|
|
||||||
|
gots, err := chase.scrape2021(message)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(gots) != 1 {
|
||||||
|
t.Fatal(gots)
|
||||||
|
}
|
||||||
|
got := gots[0]
|
||||||
|
|
||||||
|
if got.Account != "8824" {
|
||||||
|
t.Fatalf("bad account: %v: %+v", got.Account, got)
|
||||||
|
}
|
||||||
|
if got.Amount != "100.00" {
|
||||||
|
t.Fatalf("bad amount: %v: %+v", got.Amount, got)
|
||||||
|
}
|
||||||
|
if got.Vendor != "Payment" {
|
||||||
|
t.Fatalf("bad vendor: %v: %+v", got.Vendor, got)
|
||||||
|
}
|
||||||
|
t.Logf("%+v", got)
|
||||||
|
}
|
||||||
|
|
||||||
func TestScrapeChase2021(t *testing.T) {
|
func TestScrapeChase2021(t *testing.T) {
|
||||||
b, err := ioutil.ReadFile("./testdata/chase.2021.txt")
|
b, err := ioutil.ReadFile("./testdata/chase.2021.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -73,3 +108,73 @@ func TestScrapeChase2020(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Logf("%+v", got)
|
t.Logf("%+v", got)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestScrapeBofAPayment(t *testing.T) {
|
||||||
|
b, err := ioutil.ReadFile("./testdata/bofa.payment.txt")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
message := &mail.Message{
|
||||||
|
Header: map[string][]string{
|
||||||
|
"Subject": []string{"Confirmation: Thanks for Your Credit Card Payment"},
|
||||||
|
},
|
||||||
|
Body: bytes.NewReader(b),
|
||||||
|
}
|
||||||
|
bofa := &bankOfAmericaScraper{}
|
||||||
|
|
||||||
|
gots, err := bofa.scrape(message)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(gots) != 1 {
|
||||||
|
t.Fatal(len(gots))
|
||||||
|
}
|
||||||
|
got := gots[0]
|
||||||
|
want := Transaction{
|
||||||
|
ID: got.ID,
|
||||||
|
Bank: BankOfAmerica,
|
||||||
|
Amount: "-251.74",
|
||||||
|
Vendor: "Payment",
|
||||||
|
Date: "[]",
|
||||||
|
Account: BankOfAmerica.String(),
|
||||||
|
}
|
||||||
|
if *got != want {
|
||||||
|
t.Fatalf("want:\n\t%+v, got\n\t%+v", want, *got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestScrapeBofACharge(t *testing.T) {
|
||||||
|
b, err := ioutil.ReadFile("./testdata/bofa.charge.txt")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
message := &mail.Message{
|
||||||
|
Header: map[string][]string{
|
||||||
|
"Subject": []string{"Credit card transaction exceeds alert limit you set"},
|
||||||
|
},
|
||||||
|
Body: bytes.NewReader(b),
|
||||||
|
}
|
||||||
|
bofa := &bankOfAmericaScraper{}
|
||||||
|
|
||||||
|
gots, err := bofa.scrape(message)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(gots) != 1 {
|
||||||
|
t.Fatal(len(gots))
|
||||||
|
}
|
||||||
|
got := gots[0]
|
||||||
|
want := Transaction{
|
||||||
|
ID: got.ID,
|
||||||
|
Bank: BankOfAmerica,
|
||||||
|
Amount: "75.08",
|
||||||
|
Vendor: "PAYPAL GIBBDOGENTE MA",
|
||||||
|
Date: "[]",
|
||||||
|
Account: BankOfAmerica.String(),
|
||||||
|
}
|
||||||
|
if *got != want {
|
||||||
|
t.Fatalf("want:\n\t%+v, got\n\t%+v", want, *got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
46
testdata/bofa.charge.txt
vendored
Normal file
46
testdata/bofa.charge.txt
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
|
||||||
|
Credit card transaction exceeds alert limit you set
|
||||||
|
|
||||||
|
National Education Association World Mas ending in 7522
|
||||||
|
|
||||||
|
Amount: $75=2E08
|
||||||
|
Date: September 05, 2021
|
||||||
|
Where: PAYPAL GIBBDOGENTE MA
|
||||||
|
|
||||||
|
View details by going to
|
||||||
|
https://www=2Ebankofamerica=2Ecom/deeplink/redirect=2Ego?target=3Dbofasigni=
|
||||||
|
n&screen=3DAccounts:Home&version=3D7=2E0=2E0
|
||||||
|
|
||||||
|
If you made this purchase or payment but don=27t recognize the amount,
|
||||||
|
wait until the final purchase amount has posted before filing a dispute
|
||||||
|
claim=2E
|
||||||
|
|
||||||
|
If you don=27t recognize this activity, please contact us at the number
|
||||||
|
on the back of your card=2E
|
||||||
|
|
||||||
|
Did you know?
|
||||||
|
You can choose how you get alerts from us including text messages and
|
||||||
|
mobile notifications=2E Go to Alert Settings at
|
||||||
|
https://www=2Ebankofamerica=2Ecom/deeplink/redirect=2Ego?target=3Dalerts_se=
|
||||||
|
ttings&screen=3DAlerts:Home&gotoSetting=3Dtrue&version=3D7=2E1=2E0
|
||||||
|
|
||||||
|
|
||||||
|
We'll never ask for your personal information such as SSN or ATM PIN in
|
||||||
|
email messages=2E If you get an email that looks suspicious or you are not =
|
||||||
|
|
||||||
|
the intended recipient of this email, don't click on any links=2E Instead, =
|
||||||
|
|
||||||
|
forward to abuse@bankofamerica=2Ecom then delete it=2E
|
||||||
|
|
||||||
|
Please don't reply to this automatically generated service email=2E
|
||||||
|
Read our Privacy Notice https://www=2Ebankofamerica=2Ecom/privacy/consumer-=
|
||||||
|
privacy-notice=2Ego
|
||||||
|
Equal Housing Lender: https://www=2Ebankofamerica=2Ecom/help/equalhousing=
|
||||||
|
=2Ecfm
|
||||||
|
Bank of America, N=2EA=2E Member FDIC
|
||||||
|
(C) 2021 Bank of America Corporation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
=20
|
||||||
88
testdata/bofa.payment.txt
vendored
Normal file
88
testdata/bofa.payment.txt
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
Delivered-To: breellocaldev@gmail.com
|
||||||
|
Received: by 2002:a4f:f556:0:0:0:0:0 with SMTP id s22csp88584ivo;
|
||||||
|
Fri, 10 Sep 2021 03:09:37 -0700 (PDT)
|
||||||
|
X-Google-Smtp-Source: ABdhPJy5KOCCQILLhifnSPNnjMikzSGgZX0rSLKqSzdRkpjWyZAZB7Ml4gWSWxuiMPuJMUFQZPnF
|
||||||
|
X-Received: by 2002:a05:620a:15e8:: with SMTP id p8mr6940748qkm.27.1631268577237;
|
||||||
|
Fri, 10 Sep 2021 03:09:37 -0700 (PDT)
|
||||||
|
ARC-Seal: i=1; a=rsa-sha256; t=1631268577; cv=none;
|
||||||
|
d=google.com; s=arc-20160816;
|
||||||
|
b=fRiwZLXmORGlNgDHdYZ3g7DbcggjP3zVkUX1gIVHo3z/c4SLgmwu1FVu4qiUr7M2+6
|
||||||
|
9Ez7xjq0rG3JCLUk77q4I2MJW9pWL5LZdcMtoP9bbu5KYoZ0JwLQldFuzUOFp1qyLICc
|
||||||
|
pegPsozU1lTG3WSr2fxAi4kGgvr1PQUGd5EaeztK+u7I9SNyyOdXsgavbx0Dr+XLFAyG
|
||||||
|
eGo1WzDGy7NG8TMstFxQu+cfZiWKKtEeTFUGEjcXAUxCm/jvqK8MT1fPTwac9c66cCls
|
||||||
|
7bvBpXlmoSEmTz6NseH0DblgWZsdmGgkYZhIUS2cJaqIhGJUFxNqbMQswEXT29LrmnbG
|
||||||
|
zz0w==
|
||||||
|
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
|
||||||
|
h=content-transfer-encoding:feedback-id:message-id:list-id:reply-to
|
||||||
|
:mime-version:date:subject:to:from:dkim-signature;
|
||||||
|
bh=RNAxijcTyDxYmdzbEHMEKXkbCbc/Wnnsez0HenNHbUA=;
|
||||||
|
b=KtJdTZ9LFxfJTwq0gldceho7ktEybby+DLrKgjgjI2yUlaS4u0IJC2nDvkA21HjV1w
|
||||||
|
R2HMT4UITrQVoi9xa/fTsbdVIfEDjBl2rdbvO+gOthaonsCvxAsiQGFRPhmKHlbb1IiE
|
||||||
|
9GbgjYaf4qEZCO4nQUnMKTQPK+TalO1pX3UNPHf2/KTeAuXCUrySVKgierhZIxnkS3WQ
|
||||||
|
/GUsV4gDHMhmRKEQF8yxgLv3podfCm63iOBgOZ/CCITcKkQTFUByLQ2HdAmLo9TUXHNM
|
||||||
|
sJKv6pK7e05Dxp4ZeNKlm15c5xSo3OXoRqupvsXYCbzjvR2moBrVRSB7iwZHGL45zQXQ
|
||||||
|
OVug==
|
||||||
|
ARC-Authentication-Results: i=1; mx.google.com;
|
||||||
|
dkim=pass header.i=@ealerts.bankofamerica.com header.s=200608 header.b=niVgyX92;
|
||||||
|
spf=pass (google.com: domain of bounce-29_html-819616257-1667962-73720-2833596@bounce.ealerts.bankofamerica.com designates 68.232.194.2 as permitted sender) smtp.mailfrom=bounce-29_HTML-819616257-1667962-73720-2833596@bounce.ealerts.bankofamerica.com;
|
||||||
|
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=bankofamerica.com
|
||||||
|
Return-Path: <bounce-29_HTML-819616257-1667962-73720-2833596@bounce.ealerts.bankofamerica.com>
|
||||||
|
Received: from mta5.ealerts.bankofamerica.com (mta5.ealerts.bankofamerica.com. [68.232.194.2])
|
||||||
|
by mx.google.com with ESMTPS id a7si3031949qtn.85.2021.09.10.03.09.36
|
||||||
|
for <breellocaldev@gmail.com>
|
||||||
|
(version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
|
||||||
|
Fri, 10 Sep 2021 03:09:37 -0700 (PDT)
|
||||||
|
Received-SPF: pass (google.com: domain of bounce-29_html-819616257-1667962-73720-2833596@bounce.ealerts.bankofamerica.com designates 68.232.194.2 as permitted sender) client-ip=68.232.194.2;
|
||||||
|
Authentication-Results: mx.google.com;
|
||||||
|
dkim=pass header.i=@ealerts.bankofamerica.com header.s=200608 header.b=niVgyX92;
|
||||||
|
spf=pass (google.com: domain of bounce-29_html-819616257-1667962-73720-2833596@bounce.ealerts.bankofamerica.com designates 68.232.194.2 as permitted sender) smtp.mailfrom=bounce-29_HTML-819616257-1667962-73720-2833596@bounce.ealerts.bankofamerica.com;
|
||||||
|
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=bankofamerica.com
|
||||||
|
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; s=200608; d=ealerts.bankofamerica.com;
|
||||||
|
h=From:To:Subject:Date:MIME-Version:Reply-To:List-ID:X-CSA-Complaints:
|
||||||
|
Message-ID:Content-Type:Content-Transfer-Encoding;
|
||||||
|
i=onlinebanking@ealerts.bankofamerica.com;
|
||||||
|
bh=RNAxijcTyDxYmdzbEHMEKXkbCbc/Wnnsez0HenNHbUA=;
|
||||||
|
b=niVgyX923ETmQwhHEaUcs91DEv/nznIH0c7CyqIgwu0h5KtgJZIKbkIw3inZNwLL9hF+/7lfV57q
|
||||||
|
ZYXmHQVV1aXIqJLQDD5RlAq2YZvghgLdglRBbq5N9cCDTsKIA3VlrKicwN+sAwDq2JlfBv4I8rzw
|
||||||
|
Vcmfup5eqf0vJnn6k9c=
|
||||||
|
Received: by mta5.ealerts.bankofamerica.com id h7cne22fmd4j for <breellocaldev@gmail.com>; Fri, 10 Sep 2021 10:09:35 +0000 (envelope-from <bounce-29_HTML-819616257-1667962-73720-2833596@bounce.ealerts.bankofamerica.com>)
|
||||||
|
From: "Bank of America" <onlinebanking@ealerts.bankofamerica.com>
|
||||||
|
To: <breellocaldev@gmail.com>
|
||||||
|
Subject: Confirmation: Thanks for Your Credit Card Payment
|
||||||
|
Date: Fri, 10 Sep 2021 04:09:32 -0600
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Reply-To: "Bank of America" <reply-fe8a157673630d7b77-29_HTML-819616257-73720-2833596@ealerts.bankofamerica.com>
|
||||||
|
List-ID: <71108.xt.local>
|
||||||
|
X-CSA-Complaints: whitelistcomplaints@eco.de
|
||||||
|
x-job: 73720_1667962
|
||||||
|
Message-ID: <3fb2377b-699b-411c-9ea5-a3b8817aa853@las1s04mta1081.xt.local>
|
||||||
|
Feedback-ID: 73720:1667962:68.232.194.2:sfmktgcld
|
||||||
|
Content-Type: text/plain;
|
||||||
|
charset="iso-8859-1"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
Hi, BEL, we've received your credit card payment
|
||||||
|
|
||||||
|
Payment: $251.74
|
||||||
|
To: National Education Association World Mas ending in - 7522
|
||||||
|
Date posted: September 09, 2021
|
||||||
|
|
||||||
|
Sign in to bankofamerica.com to view your account details.
|
||||||
|
|
||||||
|
Thank you for being our customer.
|
||||||
|
|
||||||
|
We'll never ask for your personal information such as SSN or ATM PIN in
|
||||||
|
email messages. If you get an email that looks suspicious or you are
|
||||||
|
not the intended recipient of this email, don't click on any links.
|
||||||
|
Instead, forward to abuse@bankofamerica.com then delete it.
|
||||||
|
|
||||||
|
Please don't reply to this automatically generated service email.
|
||||||
|
Read our Privacy Notice https://www.bankofamerica.com/privacy/consumer-privacy-notice.go
|
||||||
|
Equal Housing Lender: https://www.bankofamerica.com/help/equalhousing.cfm
|
||||||
|
Bank of America, N.A. Member FDIC
|
||||||
|
(C) 2019 Bank of America Corporation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
310
testdata/chase.2021.payment.txt
vendored
Normal file
310
testdata/chase.2021.payment.txt
vendored
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
|
||||||
|
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
|
||||||
|
w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns=3D"http://www.w3.org/1999/xhtml" lang=3D"en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3DUTF-8" />
|
||||||
|
<meta name=3D"viewport" content=3D"width=3Ddevice-width, initial-scale=3D1.=
|
||||||
|
0"/>
|
||||||
|
<title>This payment has been applied to your account.</title>
|
||||||
|
</head>
|
||||||
|
<body style=3D"padding: 0px;margin: 0px; background-color:#d7dbe0;">
|
||||||
|
<table align=3D"center" width=3D"100%" border=3D"0" cellspacing=3D"0" cellp=
|
||||||
|
adding=3D"0" style=3D"min-width:800px; background-color:#d7dbe0;" class=3D"=
|
||||||
|
fullWidth">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"center" style=3D"vertical-align:top; padding:0px 0px 20px =
|
||||||
|
0px; min-width:800px; background-color:#d7dbe0;" class=3D"fullWidth"><table=
|
||||||
|
align=3D"center" width=3D"800" cellpadding=3D"0" cellspacing=3D"0" border=
|
||||||
|
=3D"0" class=3D"fullWidth" style=3D"background-color:#FFFFFF;">
|
||||||
|
<!-- Start of Content -->
|
||||||
|
<tr>
|
||||||
|
<td align=3D"center" style=3D"vertical-align:top; padding: 23px 0=
|
||||||
|
px 0px;background-color: #005EB8;"><table cellpadding=3D"0" cellspacing=3D"=
|
||||||
|
0" border=3D"0">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"right" style=3D"vertical-align:bottom; padding=
|
||||||
|
:0px 0px; width:12px;"><img src=3D"https://www.chase.com/content/dam/email/=
|
||||||
|
images/blue-left.jpg" width=3D"12" height=3D"226" border=3D"0" style=3D"dis=
|
||||||
|
play:block;" alt=3D""/></td>
|
||||||
|
<td align=3D"center" style=3D"vertical-align:bottom; paddin=
|
||||||
|
g: 0px 0px 0px;width:616px; background-color: #FFFFFF;"><table width=3D"100=
|
||||||
|
%" cellpadding=3D"0" cellspacing=3D"0" border=3D"0">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top; paddi=
|
||||||
|
ng: 0px 0px; background-color: #ffffff;"><table width=3D"100%" cellpadding=
|
||||||
|
=3D"0" cellspacing=3D"0" border=3D"0">
|
||||||
|
<!-- Start hidden preview text -->
|
||||||
|
<div style=3D"display: none; max-height: 0px; ove=
|
||||||
|
rflow: hidden;">This payment has been applied to your account.</div>
|
||||||
|
|
||||||
|
<!-- Insert ‌ after hidden preview tex=
|
||||||
|
t -->
|
||||||
|
|
||||||
|
<div style=3D"display: none; max-height: 0px; ove=
|
||||||
|
rflow: hidden;"> ‌ ‌ ‌ ‌ &zwn=
|
||||||
|
j; ‌ ‌ ‌ ‌ ‌ ‌&=
|
||||||
|
nbsp;‌ ‌ ‌ ‌ ‌ &zwn=
|
||||||
|
j; ‌ ‌ ‌ ‌ ‌ ‌&=
|
||||||
|
nbsp;‌ ‌ ‌ ‌ ‌ ‌&nbs=
|
||||||
|
p;‌ ‌ ‌ ‌ ‌ ‌ &=
|
||||||
|
zwnj; ‌ ‌ ‌ ‌ ‌ &zwn=
|
||||||
|
j; ‌ ‌ ‌ ‌ ‌ ‌&=
|
||||||
|
nbsp;‌ ‌ ‌ ‌ ‌ ‌&nbs=
|
||||||
|
p;‌ ‌ ‌ ‌ ‌ ‌ &=
|
||||||
|
zwnj; ‌ ‌ ‌ ‌ ‌&nbs=
|
||||||
|
p;‌ ‌ ‌ ‌ ‌ ‌ &=
|
||||||
|
zwnj; ‌ ‌ ‌ ‌ ‌ &zwn=
|
||||||
|
j; ‌ ‌ ‌ ‌ ‌ ‌&=
|
||||||
|
nbsp;‌ ‌ ‌ ‌ ‌ ‌&nbs=
|
||||||
|
p;‌ ‌ ‌ ‌ ‌ ‌ &=
|
||||||
|
zwnj; ‌ ‌ ‌ ‌ ‌ &zwn=
|
||||||
|
j; </div>
|
||||||
|
<!-- End hidden preview text -->
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top;=
|
||||||
|
padding-left: 30px; background-color: #ffffff;" class=3D"moPad"><table widt=
|
||||||
|
h=3D"100%" cellpadding=3D"0" cellspacing=3D"0" border=3D"0">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-alig=
|
||||||
|
n:bottom; padding:36px 0px 20px;"><img src=3D"https://www.chase.com/content=
|
||||||
|
/dam/email/images/chase-logo-h-rgb.png" width=3D"104" height=3D"20" border=
|
||||||
|
=3D"0" style=3D"display:block;" alt=3D"Chase Logo"/></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top;=
|
||||||
|
padding: 20px 28px 0px;" class=3D"moPad"><table align=3D"left" cellpadding=
|
||||||
|
=3D"0" cellspacing=3D"0" border=3D"0">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-alig=
|
||||||
|
n:top;"><table width=3D"100%" cellpadding=3D"0" cellspacing=3D"0" border=3D=
|
||||||
|
"0">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertica=
|
||||||
|
l-align:top; padding:5px 10px; font-family:Arial, Helvetica, sans-serif; fo=
|
||||||
|
nt-size:12px; font-weight:bold; color:#000000; background-color:#24e16b; bo=
|
||||||
|
rder-radius:20px; -moz-border-radius: 20px; -webkit-border-radius:20px; whi=
|
||||||
|
te-space: nowrap;" class=3D"font14">Payment received</td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top;=
|
||||||
|
background-color: #ffffff;"><table width=3D"100%" cellpadding=3D"0" cellsp=
|
||||||
|
acing=3D"0" border=3D"0">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-alig=
|
||||||
|
n:top; padding: 20px 30px 28px;" class=3D"moPad"><table width=3D"100%" cell=
|
||||||
|
padding=3D"0" cellspacing=3D"0" border=3D"0">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertica=
|
||||||
|
l-align:top; padding: 0px 20px 0px 0px;"><img src=3D"https://static.chasecd=
|
||||||
|
n.com/content/services/rendition/image.small.png/unified-assets/digital-car=
|
||||||
|
ds/aarp/41473417018.png" width=3D"57" height=3D"auto" alt=3D"" border=3D"0=
|
||||||
|
" style=3D"display:block;"/></td>
|
||||||
|
<td align=3D"left" style=3D"vertica=
|
||||||
|
l-align:top; padding:0px 50px 0px 0px; font-family:Arial, Helvetica, sans-s=
|
||||||
|
erif; font-size:30px; font-weight: bold; color:#414042;" class=3D"zeroPad">=
|
||||||
|
We've received your credit card payment</td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:bottom; padding:=
|
||||||
|
0px 0px;width:12px; "><img src=3D"https://www.chase.com/content/dam/email/i=
|
||||||
|
mages/blue-right.jpg " width=3D"12" height=3D"226" border=3D"0" style=3D"di=
|
||||||
|
splay:block;" alt=3D""/></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"center" style=3D"vertical-align:top; padding: 0px 0p=
|
||||||
|
x 0px; background-color: #FFFFFF;"><table cellpadding=3D"0" cellspacing=3D"=
|
||||||
|
0" border=3D"0">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"right" style=3D"vertical-align:top; padding:0p=
|
||||||
|
x 0px; width:12px;"><img src=3D"https://www.chase.com/content/dam/email/ima=
|
||||||
|
ges/white-left.jpg" width=3D"12" height=3D"77" border=3D"0" style=3D"displa=
|
||||||
|
y:block;" alt=3D""/></td>
|
||||||
|
<td align=3D"center" style=3D"vertical-align:top; padding: =
|
||||||
|
0px 0px 0px;width:616px;"><table width=3D"100%" cellpadding=3D"0" cellspaci=
|
||||||
|
ng=3D"0" border=3D"0">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top; paddi=
|
||||||
|
ng:0px 150px 20px 30px; font-family:Arial, Helvetica, sans-serif; font-size=
|
||||||
|
:16px; color:#414042;" class=3D"moPad">This payment has been applied to you=
|
||||||
|
r account.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top; paddi=
|
||||||
|
ng: 0px 150px 0px 30px;" class=3D"moPad"><table width=3D"100%" cellpadding=
|
||||||
|
=3D"0" cellspacing=3D"0" border=3D"0">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top;=
|
||||||
|
padding: 10px 0px;border-bottom: solid 1px #414042;"><table width=3D"100%"=
|
||||||
|
cellpadding=3D"0" cellspacing=3D"0" border=3D"0">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-alig=
|
||||||
|
n:top; padding:0px 0px 0px 0px; font-family:Arial, Helvetica, sans-serif; f=
|
||||||
|
ont-size:16px; color:#414042;" class=3D"font14">Account</td>
|
||||||
|
<td align=3D"right" style=3D"vertical-ali=
|
||||||
|
gn:top; padding:0px 0px 0px 5px; font-family:Arial, Helvetica, sans-serif; =
|
||||||
|
font-size:16px; font-weight:bold; color:#414042;" class=3D"font14">AARP fro=
|
||||||
|
m Chase (...8824)</td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top;=
|
||||||
|
padding: 10px 0px;border-bottom: solid 1px #414042;"><table width=3D"100%"=
|
||||||
|
cellpadding=3D"0" cellspacing=3D"0" border=3D"0">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-alig=
|
||||||
|
n:top; padding:0px 0px 0px 0px; font-family:Arial, Helvetica, sans-serif; f=
|
||||||
|
ont-size:16px; color:#414042;" class=3D"font14">Posted date</td>
|
||||||
|
<td align=3D"right" style=3D"vertical-ali=
|
||||||
|
gn:top; padding:0px 0px 0px 5px; font-family:Arial, Helvetica, sans-serif; =
|
||||||
|
font-size:16px; font-weight:bold; color:#414042;" class=3D"font14">Jul 30, =
|
||||||
|
2021</td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top;=
|
||||||
|
padding: 10px 0px;border-bottom: solid 1px #414042;"><table width=3D"100%"=
|
||||||
|
cellpadding=3D"0" cellspacing=3D"0" border=3D"0">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-alig=
|
||||||
|
n:top; padding:0px 0px 0px 0px; font-family:Arial, Helvetica, sans-serif; f=
|
||||||
|
ont-size:16px; color:#414042;" class=3D"font14">Payment amount</td>
|
||||||
|
<td align=3D"right" style=3D"vertical-ali=
|
||||||
|
gn:top; padding:0px 0px 0px 5px; font-family:Arial, Helvetica, sans-serif; =
|
||||||
|
font-size:16px; font-weight:bold; color:#414042;" class=3D"font14"><span cl=
|
||||||
|
ass=3D"applelinksgray41"><a style=3D"color:#414042;text-decoration: none;">=
|
||||||
|
$100.00</a></span></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top; paddi=
|
||||||
|
ng:40px 150px 40px 30px; font-family:Arial, Helvetica, sans-serif; font-siz=
|
||||||
|
e:16px; color:#414042;" class=3D"moPad">Find <a style=3D"text-decoration: u=
|
||||||
|
nderline; color:#0060F0;" href=3D"https://www.chase.com/personal/credit-car=
|
||||||
|
ds/login-epay" rel=3D"noopener noreferrer" target=3D"_blank">more informat=
|
||||||
|
ion</a> about the credit card payments process.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top;"><tab=
|
||||||
|
le width=3D"100%" align=3D"left" cellpadding=3D"0" cellspacing=3D"0" border=
|
||||||
|
=3D"0">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top;=
|
||||||
|
"><table width=3D"100%" align=3D"left" cellpadding=3D"0" cellspacing=3D"0" =
|
||||||
|
border=3D"0" class=3D"fullWidth">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"padding:0px; =
|
||||||
|
vertical-align:top; padding: 0px 0px 30px 30px;" class=3D"moPad"><table ali=
|
||||||
|
gn=3D"left" cellpadding=3D"0" cellspacing=3D"0" border=3D"0" style=3D"verti=
|
||||||
|
cal-align:top;">
|
||||||
|
<tr>
|
||||||
|
<td role=3D"button" align=3D"center=
|
||||||
|
" style=3D"background-color:#0060f0; color: #fffffe; font-size: 16px; font-=
|
||||||
|
family: Arial, Helvetica, sans-serif; padding: 10px 0px; border: 1px solid =
|
||||||
|
#0060f0; vertical-align:top; border-radius:4px; -moz-border-radius: 4px; -w=
|
||||||
|
ebkit-border-radius:4px;width: 200px;"><a href=3D"https://www.chase.com/per=
|
||||||
|
sonal/mobile-online-banking/payment-activity" target=3D"_blank" style=3D"co=
|
||||||
|
lor: #fffffe; text-decoration:none;">See payment activity</a></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top; paddi=
|
||||||
|
ng:0px 30px 20px; font-family:Arial, Helvetica, sans-serif; font-size:12px;=
|
||||||
|
color:#717171;" class=3D"moPad font14">Securely access your accounts with =
|
||||||
|
the <a style=3D"text-decoration: underline; color:#0060F0;" href=3D"https:/=
|
||||||
|
/www.chase.com/digital/mobile-banking" rel=3D"noopener noreferrer" target=
|
||||||
|
=3D"_blank">Chase Mobile<span style=3D"font-size:70%; line-height:0; v=
|
||||||
|
ertical-align:3px; text-decoration: none;">®</span> app</a> or <a style=
|
||||||
|
=3D"text-decoration: underline; color:#0060F0;" href=3D"https://secure.chas=
|
||||||
|
e.com/web/auth/nav?navKey=3DrequestDashboard" rel=3D"noopener noreferrer" =
|
||||||
|
target=3D"_blank">chase.com</a>. </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top; paddi=
|
||||||
|
ng: 0px 0px; background-color: #F6F6F6;"><table width=3D"100%" cellpadding=
|
||||||
|
=3D"0" cellspacing=3D"0" border=3D"0">
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top;=
|
||||||
|
padding:20px 30px 60px; font-family:Arial, Helvetica, sans-serif; font-siz=
|
||||||
|
e:12px; color:#717171;" class=3D"moPad font14"><span role=3D"heading" style=
|
||||||
|
=3D"text-transform: uppercase; font-weight: bold;">About this message</span=
|
||||||
|
><br />
|
||||||
|
<br />
|
||||||
|
Chase Mobile<span style=3D"font-size:70%=
|
||||||
|
; line-height:0; vertical-align:3px;">®</span> app is available for se=
|
||||||
|
lect mobile devices. Message and data rates may apply.<br />
|
||||||
|
<br />
|
||||||
|
This service email was sent based on your ale=
|
||||||
|
rt settings. Use the Chase Mobile app or visit <a href=3D"https://www.=
|
||||||
|
chase.com/personal/mobile-online-banking/login-alerts" target=3D"_blank" st=
|
||||||
|
yle=3D"text-decoration: underline; color:#0060F0;" rel=3D"noopener noreferr=
|
||||||
|
er">chase.com/alerts</a> to view or manage your settings.<br />
|
||||||
|
<br />
|
||||||
|
Chase cannot guarantee the delivery of alerts=
|
||||||
|
and notifications. Wireless or internet service provider outages or other =
|
||||||
|
circumstances could delay them. You can always check <span class=3D"appleli=
|
||||||
|
nksgray"><a style=3D"color:#717171;text-decoration: none;">chase.com</a></s=
|
||||||
|
pan> or the Chase Mobile app for the status of your accounts including=
|
||||||
|
your latest account balances and transaction details.<br />
|
||||||
|
<br />
|
||||||
|
To protect your personal information, please =
|
||||||
|
don't reply to this message. Chase won't ask for confidential information i=
|
||||||
|
n an email. <br />
|
||||||
|
<br />
|
||||||
|
If you have concerns about the authenticity o=
|
||||||
|
f this message or have questions about your account visit <a style=3D"text-=
|
||||||
|
decoration: underline; color:#0060F0;" href=3D"https://www.chase.com/digita=
|
||||||
|
l/customer-service" target=3D"_blank" rel=3D"noopener noreferrer">chase.com=
|
||||||
|
/CustomerService</a> for ways to contact us.<br />
|
||||||
|
<br />
|
||||||
|
Your privacy is important to us. See our onli=
|
||||||
|
ne <a style=3D"text-decoration: underline; color:#0060F0;" href=3D"https://=
|
||||||
|
www.chase.com/digital/resources/privacy-security" target=3D"_blank" rel=3D"=
|
||||||
|
noopener noreferrer">Security Center</a> to learn how to protect your infor=
|
||||||
|
mation.<br />
|
||||||
|
<br />
|
||||||
|
© 2021 JPMorgan Chase & Co. </td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
<td align=3D"left" style=3D"vertical-align:top; padding:0px=
|
||||||
|
0px; width:12px;"><img src=3D"https://www.chase.com/content/dam/email/imag=
|
||||||
|
es/white-right.jpg" width=3D"12" height=3D"77" border=3D"0" style=3D"displa=
|
||||||
|
y:block;" alt=3D""/></td>
|
||||||
|
</tr>
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
<!--End of Content -->
|
||||||
|
|
||||||
|
</table></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ func (t *Transaction) Format() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transaction) String() string {
|
func (t *Transaction) String() string {
|
||||||
return fmt.Sprint(*t)
|
return fmt.Sprintf("%+v", *t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTransaction(account, amount, vendor, date string, bank Bank) *Transaction {
|
func NewTransaction(account, amount, vendor, date string, bank Bank) *Transaction {
|
||||||
|
|||||||
Reference in New Issue
Block a user