From b30d9da948585220834e613e9484329718a6af8f Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 9 Oct 2026 20:58:31 +0000 Subject: [PATCH] Add email verification inputs Add the was_verification_successful and verification_time attributes to Email. They describe the most recent verification of the email address. With validation on, the result must be a boolean and the time must be an RFC 3339 date-time. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 3 +++ README.md | 6 ++++-- lib/minfraud/components/email.rb | 25 ++++++++++++++++++++--- spec/components/email_spec.rb | 35 +++++++++++++++++++++++++++++++- 4 files changed, 63 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c33876..1498cca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ `phone_was_verification_successful`, and `phone_verification_time` attributes to `Minfraud::Components::Billing`. They describe the most recent verification of the billing phone number. +* Added the `was_verification_successful` and `verification_time` + attributes to `Minfraud::Components::Email`. They describe the most + recent verification of the email address. * Boolean inputs are now always sent as JSON booleans, and `false` values are no longer dropped from the request. Previously, `false` was omitted for every boolean input. `true` was sent as the string `"true"` for diff --git a/README.md b/README.md index 5d4c7bd..648bc22 100644 --- a/README.md +++ b/README.md @@ -98,8 +98,10 @@ assessment = Minfraud::Assessments.new( username_md5: '4f9726678c438914fa04bdb8c1a24088', }, email: { - address: 'test@maxmind.com', - domain: 'maxmind.com', + address: 'test@maxmind.com', + domain: 'maxmind.com', + verification_time: '2026-10-01T14:30:00Z', + was_verification_successful: true, }, billing: { first_name: 'First', diff --git a/lib/minfraud/components/email.rb b/lib/minfraud/components/email.rb index 726c33f..ac3eca1 100644 --- a/lib/minfraud/components/email.rb +++ b/lib/minfraud/components/email.rb @@ -31,12 +31,29 @@ class Email < Base # @return [Boolean, nil] attr_accessor :hash_address + # Whether the most recent verification of the email address succeeded. + # Do not include this field if no verification was attempted. + # + # @return [Boolean, nil] + attr_accessor :was_verification_successful + + # The date and time of the most recent verification of the email + # address. The string must be in the RFC 3339 date-time format, e.g., + # "2012-04-12T23:20:50.52Z". + # + # @see https://datatracker.ietf.org/doc/html/rfc3339 + # + # @return [String, nil] + attr_accessor :verification_time + # @param params [Hash] Hash of parameters. Each key/value should # correspond to one of the available attributes. def initialize(params = {}) - @address = params[:address] - @domain = params[:domain] - @hash_address = params[:hash_address] + @address = params[:address] + @domain = params[:domain] + @hash_address = params[:hash_address] + @was_verification_successful = params[:was_verification_successful] + @verification_time = params[:verification_time] validate end @@ -72,6 +89,8 @@ def validate validate_email('email', @address) validate_string('domain', 255, @domain) + validate_boolean('was_verification_successful', @was_verification_successful) + validate_rfc3339('verification_time', @verification_time) end def hash_email_address(address) diff --git a/spec/components/email_spec.rb b/spec/components/email_spec.rb index d1297e9..27c57ec 100644 --- a/spec/components/email_spec.rb +++ b/spec/components/email_spec.rb @@ -3,6 +3,21 @@ require 'spec_helper' describe Minfraud::Components::Email do + describe '#to_json' do + [true, false].each do |successful| + it "sends was_verification_successful #{successful} as a JSON boolean" do + email = described_class.new( + verification_time: '2026-10-01T14:30:00Z', + was_verification_successful: successful, + ) + expect(email.to_json).to eq( + 'verification_time' => '2026-10-01T14:30:00Z', + 'was_verification_successful' => successful, + ) + end + end + end + describe 'validation' do before do Minfraud.configure { |c| c.enable_validation = 1 } @@ -16,9 +31,27 @@ end.to raise_exception(Minfraud::InvalidInputError) end + it 'raises an exception for an invalid was_verification_successful' do + expect do + described_class.new( + was_verification_successful: 'true', + ) + end.to raise_exception(Minfraud::InvalidInputError) + end + + it 'raises an exception for an invalid verification_time' do + expect do + described_class.new( + verification_time: '2026-10-01 14:30:00', + ) + end.to raise_exception(Minfraud::InvalidInputError) + end + it 'does not raise an exception for valid values' do described_class.new( - address: 'wstorey@maxmind.com', + address: 'wstorey@maxmind.com', + verification_time: '2026-10-01T14:30:00Z', + was_verification_successful: false, ) end