Skip to content

Commit 7af544e

Browse files
oschwaldclaude
andcommitted
Add email domain outputs for Insights and Factors
Adds support for new email domain fields: - classification, risk, and volume - visit sub-object with status, lastVisitedOn, and hasRedirect 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent dd99969 commit 7af544e

File tree

6 files changed

+143
-6
lines changed

6 files changed

+143
-6
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@ CHANGELOG
1212
* Added the input `/payment/method`. This is the payment method associated
1313
with the transaction. You may provide this by providing `method` to
1414
`Payment`.
15+
* Added the output `/email/domain/classification`. This is available as the
16+
`classification` property on `response.email.domain`.
17+
* Added the output `/email/domain/risk`. This is available as the `risk`
18+
property on `response.email.domain`.
19+
* Added the output `/email/domain/volume`. This is available as the `volume`
20+
property on `response.email.domain`.
21+
* Added the output `/email/domain/visit/status`. This is available as the
22+
`status` property on `response.email.domain.visit`.
23+
* Added the output `/email/domain/visit/last_visited_on`. This is available
24+
as the `lastVisitedOn` property on `response.email.domain.visit`.
25+
* Added the output `/email/domain/visit/has_redirect`. This is available as
26+
the `hasRedirect` property on `response.email.domain.visit`.
1527

1628
8.1.0 (2025-05-23)
1729
------------------

fixtures/insights.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,15 @@
177177

178178
"email": {
179179
"domain": {
180-
"first_seen": "2016-01-23"
180+
"classification": "business",
181+
"first_seen": "2016-01-23",
182+
"risk": 15.5,
183+
"visit": {
184+
"has_redirect": false,
185+
"last_visited_on": "2024-11-15",
186+
"status": "live"
187+
},
188+
"volume": 6300
181189
},
182190
"first_seen": "2016-02-03",
183191
"is_disposable": false,

src/response/models/insights.spec.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,34 @@ describe('Insights()', () => {
3333
const model = new Insights(response as InsightsResponse);
3434
expect(model.email?.domain?.firstSeen).toBe('2016-01-23');
3535
});
36+
37+
it('allows /email/domain/classification to be accessed', () => {
38+
const model = new Insights(response as InsightsResponse);
39+
expect(model.email?.domain?.classification).toBe('business');
40+
});
41+
42+
it('allows /email/domain/risk to be accessed', () => {
43+
const model = new Insights(response as InsightsResponse);
44+
expect(model.email?.domain?.risk).toBe(15.5);
45+
});
46+
47+
it('allows /email/domain/volume to be accessed', () => {
48+
const model = new Insights(response as InsightsResponse);
49+
expect(model.email?.domain?.volume).toBe(6300);
50+
});
51+
52+
it('allows /email/domain/visit/status to be accessed', () => {
53+
const model = new Insights(response as InsightsResponse);
54+
expect(model.email?.domain?.visit?.status).toBe('live');
55+
});
56+
57+
it('allows /email/domain/visit/last_visited_on to be accessed', () => {
58+
const model = new Insights(response as InsightsResponse);
59+
expect(model.email?.domain?.visit?.lastVisitedOn).toBe('2024-11-15');
60+
});
61+
62+
it('allows /email/domain/visit/has_redirect to be accessed', () => {
63+
const model = new Insights(response as InsightsResponse);
64+
expect(model.email?.domain?.visit?.hasRedirect).toBe(false);
65+
});
3666
});

src/response/records.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,15 +191,60 @@ export interface Device {
191191
readonly localTime: string;
192192
}
193193

194+
/**
195+
* Status of an automated visit to the email domain. This object is only
196+
* available for low-volume domains. High-volume domains (email providers,
197+
* large businesses) will not include visit data.
198+
*/
199+
export interface EmailDomainVisit {
200+
/**
201+
* Indicates if the domain redirects to another URL.
202+
*/
203+
readonly hasRedirect: boolean;
204+
/**
205+
* The date the automated visit was completed, in ISO 8601 format (YYYY-MM-DD).
206+
*/
207+
readonly lastVisitedOn: string;
208+
/**
209+
* Classification of the domain based on the automated visit.
210+
* Possible values include: `live`, `dns_error`, `network_error`,
211+
* `http_error`, `parked`, `pre_development`.
212+
*/
213+
readonly status: string;
214+
}
215+
194216
/**
195217
* This object contains information about the email address domain passed in the
196218
* request.
197219
*/
198220
export interface EmailDomain {
221+
/**
222+
* Classification of the email domain type. Possible values include:
223+
* `business`, `education`, `government`, `isp_email`.
224+
* Additional values may be added in the future.
225+
*/
226+
readonly classification?: string;
199227
/**
200228
* The date the email address domain was first seen by MaxMind.
201229
*/
202230
readonly firstSeen: string;
231+
/**
232+
* A risk score from 0.01 to 99 associated with the email domain.
233+
* Higher scores indicate higher risk.
234+
*/
235+
readonly risk?: number;
236+
/**
237+
* Information from an automated visit to the email domain. This is only
238+
* available for low-volume domains and may be initially unavailable for
239+
* newly-sighted domains, populating later after automated visits occur.
240+
*/
241+
readonly visit?: EmailDomainVisit;
242+
/**
243+
* Activity indicator for the email domain across the minFraud network,
244+
* expressed in sightings per million. Values range from 0.001 to 1,000,000
245+
* and are rounded to 2 significant figures.
246+
*/
247+
readonly volume?: number;
203248
}
204249

205250
/**

src/response/web-records.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,32 @@ export interface DeviceWebRecord {
7474
readonly local_time: string;
7575
}
7676

77+
export type EmailDomainClassification =
78+
| 'business'
79+
| 'education'
80+
| 'government'
81+
| 'isp_email';
82+
83+
export type EmailDomainVisitStatus =
84+
| 'live'
85+
| 'dns_error'
86+
| 'network_error'
87+
| 'http_error'
88+
| 'parked'
89+
| 'pre_development';
90+
91+
export interface EmailDomainVisitWebRecord {
92+
readonly has_redirect: boolean;
93+
readonly last_visited_on: string;
94+
readonly status: EmailDomainVisitStatus;
95+
}
96+
7797
export interface EmailDomainWebRecord {
98+
readonly classification?: EmailDomainClassification;
7899
readonly first_seen: string;
100+
readonly risk?: number;
101+
readonly visit?: EmailDomainVisitWebRecord;
102+
readonly volume?: number;
79103
}
80104

81105
export interface EmailWebRecord {

src/webServiceClient.spec.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ describe('WebServiceClient', () => {
3737
});
3838

3939
it('handles "full" responses', async () => {
40-
expect.assertions(174);
40+
expect.assertions(180);
4141

4242
nockInstance
4343
.post(fullPath('factors'), factors.request.basic)
@@ -211,6 +211,12 @@ describe('WebServiceClient', () => {
211211
expect(got.device?.localTime).toEqual('2018-01-02T10:40:11-08:00');
212212

213213
expect(got.email?.domain?.firstSeen).toEqual('2016-01-23');
214+
expect(got.email?.domain?.classification).toEqual('business');
215+
expect(got.email?.domain?.risk).toEqual(15.5);
216+
expect(got.email?.domain?.volume).toEqual(6300);
217+
expect(got.email?.domain?.visit?.status).toEqual('live');
218+
expect(got.email?.domain?.visit?.lastVisitedOn).toEqual('2024-11-15');
219+
expect(got.email?.domain?.visit?.hasRedirect).toEqual(false);
214220
expect(got.email?.firstSeen).toEqual('2016-02-03');
215221
expect(got.email?.isDisposable).toEqual(false);
216222
expect(got.email?.isFree).toEqual(false);
@@ -293,7 +299,7 @@ describe('WebServiceClient', () => {
293299
});
294300

295301
it('handles "full" responses', async () => {
296-
expect.assertions(149);
302+
expect.assertions(155);
297303

298304
nockInstance
299305
.post(fullPath('insights'), insights.request.basic)
@@ -467,6 +473,12 @@ describe('WebServiceClient', () => {
467473
expect(got.device?.localTime).toEqual('2018-01-02T10:40:11-08:00');
468474

469475
expect(got.email?.domain?.firstSeen).toEqual('2016-01-23');
476+
expect(got.email?.domain?.classification).toEqual('business');
477+
expect(got.email?.domain?.risk).toEqual(15.5);
478+
expect(got.email?.domain?.volume).toEqual(6300);
479+
expect(got.email?.domain?.visit?.status).toEqual('live');
480+
expect(got.email?.domain?.visit?.lastVisitedOn).toEqual('2024-11-15');
481+
expect(got.email?.domain?.visit?.hasRedirect).toEqual(false);
470482
expect(got.email?.firstSeen).toEqual('2016-02-03');
471483
expect(got.email?.isDisposable).toEqual(false);
472484
expect(got.email?.isFree).toEqual(false);
@@ -530,16 +542,16 @@ describe('WebServiceClient', () => {
530542

531543
switch (property) {
532544
case 'billing_address':
533-
expect.assertions(134);
545+
expect.assertions(140);
534546
break;
535547
case 'credit_card':
536-
expect.assertions(128);
548+
expect.assertions(134);
537549
break;
538550
case 'email':
539551
expect.assertions(134);
540552
break;
541553
case 'shipping_address':
542-
expect.assertions(132);
554+
expect.assertions(138);
543555
break;
544556
}
545557

@@ -569,6 +581,12 @@ describe('WebServiceClient', () => {
569581

570582
if (property != 'email') {
571583
expect(got.email?.domain?.firstSeen).toEqual('2016-01-23');
584+
expect(got.email?.domain?.classification).toEqual('business');
585+
expect(got.email?.domain?.risk).toEqual(15.5);
586+
expect(got.email?.domain?.volume).toEqual(6300);
587+
expect(got.email?.domain?.visit?.status).toEqual('live');
588+
expect(got.email?.domain?.visit?.lastVisitedOn).toEqual('2024-11-15');
589+
expect(got.email?.domain?.visit?.hasRedirect).toEqual(false);
572590
expect(got.email?.firstSeen).toEqual('2016-02-03');
573591
expect(got.email?.isDisposable).toEqual(false);
574592
expect(got.email?.isFree).toEqual(false);

0 commit comments

Comments
 (0)