New Interac Email Format

Christopher Vollick created

They've changed the way their emails look, so I'm changing my scraper in
response!

New format is more blocky, so things are further out. The position of
the message has changed and is different between Manual and Automatic,
so I'm scanning paragraphs looking for "Message:" now.

Also, their newline formats have changed but as also inconsistent, so
some mailings have \r\n and others just \n...
This is _actually_ the part that broke emails so they all say they "have
the wrong paragraph structure". I mean, the old ones weren't going to
work anymore anyway, but they broke so fundamentally that it wasn't even
like "Can't find money" or something because everything looked like one
paragraph.

So the wording has changed, but I'm still trying to be over-specified
because I don't want a carefully worded "Message" to trick the system.

Anyway, this'll probably be fine until later it's not...

Change summary

lib/interac_email.rb | 48 ++++++++++++++++++++++++++++-----------------
1 file changed, 30 insertions(+), 18 deletions(-)

Detailed changes

lib/interac_email.rb 🔗

@@ -38,6 +38,14 @@ class InteracEmail
 		}
 		BadMoney = err { |auto| "Dollars aren't dollars (#{auto.raw_dollars})" }
 
+		NoMessage = err { |auto|
+			"No Message in $%0.2f transfer %s from %s" %
+				[
+					auto.dollars,
+					auto.transaction_id,
+					auto.sender_name
+				]
+		}
 		NoJID = err { |auto|
 			"No JID in $%0.2f transfer %s from %s with message: %s" %
 				[
@@ -60,7 +68,7 @@ class InteracEmail
 	end
 
 	AUTO_REGEX =
-		/A +money +transfer +from .* has +been +automatically +deposited.$/
+		/and it has been automatically deposited.$/
 		.freeze
 
 	def self.for(m, id_builder: ->(id) { id.to_s })
@@ -165,35 +173,39 @@ class InteracEmail
 	end
 
 	# First one is "Hi WHOEVER"
-	# Second one is "So and so sent you this much"
-	# Third is the message
-	# Fourth is Reference number
-	# Fifth is "Do not reply"
-	# Sixth is footer
+	# Second one is "Funds Deposited!\n$NN.NN"
+	# Third is funds automatically deposited
+	# Fourth is bank account details
+	# Fifth is "Transfer Details"
+	# Sixth is "Message:\n<MESSAGE>"
+	# Seventh is a block of data with date, reference number, sender, amount
+	# Then there's a few different ones of footer
 	def paragraphs
 		# This needs to be a non-capturing group "(?:"
 		# Split does a neat thing with groups where it puts
 		# the matching groups into the returned list!
 		# Neat, but absolutely not what I want
-		text_part.decoded.split(/(?:\r\n){2,}/).tap { |v|
+		text_part.decoded.strip.split(/(?:\r\n|\n){2,}/).tap { |v|
 			# I don't really use the others, but make sure the
 			# first three are there
-			raise Error::BadParagraphs, self unless v.length > 3
+			raise Error::BadParagraphs, self unless v.length > 6
 		}
 	end
 
 	def message
-		paragraphs[2].sub(/^Message:\s*/, "")
+		# I used to hard-code a number, but it differs a bit.
+		# I figure this is safe because unlike the other fields, this is the
+		# user-provided one. So they can't really spoof themselves. It's the
+		# other fields I'd be more worried about
+		ms = paragraphs.select { |p| p.start_with?("Message:") }
+		raise Error::NoMessage, self if ms.empty?
+		ms.first.sub(/^Message:\s*/, "")
 	end
 
-	# We don't want people's names to be able to spoof a number,
-	# so consume greedily from the start
 	DOLLARS_REGEX = /
 		# This is a free-spaced regex, so literal spaces
 		# don't count as spaces in match
-		.*\s+ has\s+ sent\s+ you\s+ a\s+ money\s+ transfer\s+ for\s+ the\s+
-		amount\s+ of\s+ \$([^ ]*)\s+ \(CAD\)\s+ and\s+ the\s+ money\s+ has\s+
-		been\s+ automatically\s+ deposited\s+ into\s+ your\s+ bank\s+ account
+		Funds\s+ Deposited!\s+\$([^ ]*)
 	/x.freeze
 
 	def raw_dollars
@@ -278,8 +290,8 @@ class InteracEmail
 		REGEX = /
 			# This is a free-spaced regex, so literal spaces
 			# don't count as spaces in match
-			.*\s+ sent\s+ you\s+ a\s+ money\s+ transfer\s+ for\s+ the\s+
-			amount\s+ of\s+ \$([^ ]*)\s+ \(CAD\).
+			Your\s funds\s await!\s+
+			\$([^ ]*)
 		/x.freeze
 
 		def raw_dollars
@@ -289,8 +301,8 @@ class InteracEmail
 		end
 
 		def raw_link
-			paragraphs[4]&.delete_prefix(
-				"To deposit your money, click here:\r\n"
+			paragraphs[3]&.delete_prefix(
+				"RBC Royal Bank: "
 			)
 		end