Skip to content

Commit 8ce48bf

Browse files
oschwaldclaude
andcommitted
Add email domain outputs to minFraud Insights and Factors
This adds support for new email domain outputs including classification, risk score, volume, and automated visit status information. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 6b2381a commit 8ce48bf

5 files changed

Lines changed: 354 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@ CHANGELOG
1111
transaction.
1212
* Added the input `/payment/method`. This is the payment method associated
1313
with the transaction.
14+
* Added support for new `/email/domain/` outputs in minFraud Insights and
15+
Factors responses:
16+
* `/email/domain/classification` - categorizes the email domain type
17+
(`business`, `education`, `government`, `isp_email`)
18+
* `/email/domain/risk` - risk score associated with the domain (0.01 to 99)
19+
* `/email/domain/volume` - activity level across the minFraud network
20+
(sightings per million)
21+
* `/email/domain/visit/has_redirect` - whether the domain redirects
22+
* `/email/domain/visit/last_visited_on` - date of last automated check
23+
* `/email/domain/visit/status` - domain status (`live`, `dns_error`,
24+
`network_error`, `http_error`, `parked`, `pre_development`)
1425

1526
3.3.0 (2025-05-23)
1627
------------------

src/MinFraud/Model/EmailDomain.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,51 @@
99
*/
1010
class EmailDomain implements \JsonSerializable
1111
{
12+
/**
13+
* @var string|null The classification of the email domain. Possible values are:
14+
* - `business` - Business domain
15+
* - `education` - Educational institution domain
16+
* - `government` - Government domain
17+
* - `isp_email` - ISP email provider domain
18+
*/
19+
public readonly ?string $classification;
20+
1221
/**
1322
* @var string|null A date string (e.g. 2017-04-24) to
1423
* identify the date an email domain was first seen by MaxMind. This is
1524
* expressed using the ISO 8601 date format.
1625
*/
1726
public readonly ?string $firstSeen;
1827

28+
/**
29+
* @var float|null The risk associated with the email domain. The value ranges
30+
* from 0.01 to 99. A higher score indicates higher risk.
31+
*/
32+
public readonly ?float $risk;
33+
34+
/**
35+
* @var EmailDomainVisit an object containing information about an automated
36+
* visit to the email domain
37+
*/
38+
public readonly EmailDomainVisit $visit;
39+
40+
/**
41+
* @var float|null This field indicates how much activity is seen on the email
42+
* domain across the minFraud network, expressed in sightings per
43+
* million. The value ranges from 0.001 to 1,000,000.
44+
*/
45+
public readonly ?float $volume;
46+
1947
/**
2048
* @param array<string, mixed>|null $response
2149
*/
2250
public function __construct(?array $response)
2351
{
52+
$this->classification = $response['classification'] ?? null;
2453
$this->firstSeen = $response['first_seen'] ?? null;
54+
$this->risk = $response['risk'] ?? null;
55+
$this->visit = new EmailDomainVisit($response['visit'] ?? null);
56+
$this->volume = $response['volume'] ?? null;
2557
}
2658

2759
/**
@@ -31,10 +63,27 @@ public function jsonSerialize(): array
3163
{
3264
$js = [];
3365

66+
if ($this->classification !== null) {
67+
$js['classification'] = $this->classification;
68+
}
69+
3470
if ($this->firstSeen !== null) {
3571
$js['first_seen'] = $this->firstSeen;
3672
}
3773

74+
if ($this->risk !== null) {
75+
$js['risk'] = $this->risk;
76+
}
77+
78+
$visit = $this->visit->jsonSerialize();
79+
if (!empty($visit)) {
80+
$js['visit'] = $visit;
81+
}
82+
83+
if ($this->volume !== null) {
84+
$js['volume'] = $this->volume;
85+
}
86+
3887
return $js;
3988
}
4089
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MaxMind\MinFraud\Model;
6+
7+
/**
8+
* Model containing information about an automated visit to the email domain.
9+
*
10+
* This object provides data from MaxMind's automated checks of domain
11+
* accessibility, including whether the domain is live, has errors, or
12+
* redirects to another location.
13+
*/
14+
class EmailDomainVisit implements \JsonSerializable
15+
{
16+
/**
17+
* @var bool|null This field is present with a value of `true` if the domain
18+
* redirects to another URL. If the domain does not redirect,
19+
* this field will be `null`.
20+
*/
21+
public readonly ?bool $hasRedirect;
22+
23+
/**
24+
* @var string|null The date when MaxMind last checked the domain's
25+
* accessibility. This is expressed using the ISO 8601 date
26+
* format (YYYY-MM-DD), e.g., "2025-11-15".
27+
*/
28+
public readonly ?string $lastVisitedOn;
29+
30+
/**
31+
* @var string|null The status of the domain based on the most recent
32+
* automated check. Possible values are:
33+
* - `live` - Domain is accessible and functioning
34+
* - `dns_error` - Domain has DNS resolution issues
35+
* - `network_error` - Network connectivity issues
36+
* - `http_error` - HTTP request failed
37+
* - `parked` - Domain appears to be parked
38+
* - `pre_development` - Domain appears to be in pre-development
39+
*/
40+
public readonly ?string $status;
41+
42+
/**
43+
* @param array<string, mixed>|null $response
44+
*/
45+
public function __construct(?array $response)
46+
{
47+
$this->hasRedirect = $response['has_redirect'] ?? null;
48+
$this->lastVisitedOn = $response['last_visited_on'] ?? null;
49+
$this->status = $response['status'] ?? null;
50+
}
51+
52+
/**
53+
* @return array<string, mixed>
54+
*/
55+
public function jsonSerialize(): array
56+
{
57+
$js = [];
58+
59+
if ($this->hasRedirect !== null) {
60+
$js['has_redirect'] = $this->hasRedirect;
61+
}
62+
63+
if ($this->lastVisitedOn !== null) {
64+
$js['last_visited_on'] = $this->lastVisitedOn;
65+
}
66+
67+
if ($this->status !== null) {
68+
$js['status'] = $this->status;
69+
}
70+
71+
return $js;
72+
}
73+
}

tests/MaxMind/Test/MinFraud/Model/EmailDomainTest.php

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,130 @@
1414
*/
1515
class EmailDomainTest extends TestCase
1616
{
17-
public function testEmailDomain(): void
17+
public function testEmailDomainFull(): void
1818
{
1919
$array = [
20+
'classification' => 'business',
2021
'first_seen' => '2017-01-02',
22+
'risk' => 1.23,
23+
'visit' => [
24+
'has_redirect' => true,
25+
'last_visited_on' => '2025-11-15',
26+
'status' => 'live',
27+
],
28+
'volume' => 6.5,
2129
];
2230
$email = new EmailDomain($array);
2331

32+
$this->assertSame(
33+
$array['classification'],
34+
$email->classification,
35+
'classification'
36+
);
37+
38+
$this->assertSame(
39+
$array['first_seen'],
40+
$email->firstSeen,
41+
'firstSeen'
42+
);
43+
44+
$this->assertSame(
45+
$array['risk'],
46+
$email->risk,
47+
'risk'
48+
);
49+
50+
$this->assertTrue(
51+
$email->visit->hasRedirect,
52+
'visit->hasRedirect'
53+
);
54+
55+
$this->assertSame(
56+
$array['visit']['last_visited_on'],
57+
$email->visit->lastVisitedOn,
58+
'visit->lastVisitedOn'
59+
);
60+
61+
$this->assertSame(
62+
$array['visit']['status'],
63+
$email->visit->status,
64+
'visit->status'
65+
);
66+
67+
$this->assertSame(
68+
$array['volume'],
69+
$email->volume,
70+
'volume'
71+
);
72+
73+
$this->assertSame(
74+
$array,
75+
$email->jsonSerialize(),
76+
'jsonSerialize'
77+
);
78+
}
79+
80+
public function testEmailDomainEmpty(): void
81+
{
82+
$email = new EmailDomain(null);
83+
84+
$this->assertNull($email->classification, 'classification');
85+
$this->assertNull($email->firstSeen, 'firstSeen');
86+
$this->assertNull($email->risk, 'risk');
87+
$this->assertNull($email->visit->hasRedirect, 'visit->hasRedirect');
88+
$this->assertNull($email->visit->lastVisitedOn, 'visit->lastVisitedOn');
89+
$this->assertNull($email->visit->status, 'visit->status');
90+
$this->assertNull($email->volume, 'volume');
91+
92+
$this->assertSame(
93+
[],
94+
$email->jsonSerialize(),
95+
'jsonSerialize'
96+
);
97+
}
98+
99+
public function testEmailDomainPartial(): void
100+
{
101+
$array = [
102+
'first_seen' => '2017-01-02',
103+
'risk' => 42.5,
104+
];
105+
$email = new EmailDomain($array);
106+
107+
$this->assertNull($email->classification, 'classification is null');
108+
24109
$this->assertSame(
25110
$array['first_seen'],
26111
$email->firstSeen,
27112
'firstSeen'
28113
);
114+
115+
$this->assertSame(
116+
$array['risk'],
117+
$email->risk,
118+
'risk'
119+
);
120+
121+
$this->assertNull($email->volume, 'volume is null');
122+
123+
$this->assertSame(
124+
$array,
125+
$email->jsonSerialize(),
126+
'jsonSerialize only includes present fields'
127+
);
128+
}
129+
130+
public function testEmailDomainClassificationValues(): void
131+
{
132+
$classifications = ['business', 'education', 'government', 'isp_email'];
133+
134+
foreach ($classifications as $classification) {
135+
$email = new EmailDomain(['classification' => $classification]);
136+
$this->assertSame(
137+
$classification,
138+
$email->classification,
139+
"classification value: {$classification}"
140+
);
141+
}
29142
}
30143
}

0 commit comments

Comments
 (0)