Some checks are pending
continuous-integration/drone/push Build is running
Closes: #36
1361 lines
40 KiB
YAML
1361 lines
40 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: happyDeliver API
|
|
description: Email Deliverability Testing Platform API
|
|
version: 0.1.0
|
|
contact:
|
|
name: happyDomain team
|
|
url: https://github.com/happyDomain/happydeliver
|
|
email: contact+api@happydomain.org
|
|
license:
|
|
name: GNU Affero General Public License v3.0 or later
|
|
url: https://spdx.org/licenses/AGPL-3.0-or-later.html
|
|
|
|
servers:
|
|
- url: http://localhost:8080/api
|
|
description: Local development server
|
|
- url: https://api.example.com/api
|
|
description: Production server
|
|
|
|
tags:
|
|
- name: tests
|
|
description: Test management operations
|
|
- name: reports
|
|
description: Report retrieval operations
|
|
- name: health
|
|
description: Service health and status
|
|
|
|
paths:
|
|
/test:
|
|
post:
|
|
tags:
|
|
- tests
|
|
summary: Create a new deliverability test
|
|
description: Generates a unique test email address for sending test emails. No database record is created until an email is received.
|
|
operationId: createTest
|
|
responses:
|
|
'201':
|
|
description: Test email address generated successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TestResponse'
|
|
'500':
|
|
description: Internal server error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/test/{id}:
|
|
get:
|
|
tags:
|
|
- tests
|
|
summary: Get test status
|
|
description: Check if a report exists for the given test ID (base32-encoded). Returns pending if no report exists, analyzed if a report is available.
|
|
operationId: getTest
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
pattern: '^[a-z0-9-]+$'
|
|
description: Base32-encoded test ID (with hyphens)
|
|
responses:
|
|
'200':
|
|
description: Test status retrieved successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Test'
|
|
'500':
|
|
description: Internal server error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/report/{id}:
|
|
get:
|
|
tags:
|
|
- reports
|
|
summary: Get detailed report
|
|
description: Retrieve comprehensive deliverability analysis report
|
|
operationId: getReport
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
pattern: '^[a-z0-9-]+$'
|
|
description: Base32-encoded test ID (with hyphens)
|
|
responses:
|
|
'200':
|
|
description: Report retrieved successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Report'
|
|
'404':
|
|
description: Report not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/report/{id}/raw:
|
|
get:
|
|
tags:
|
|
- reports
|
|
summary: Get raw annotated email
|
|
description: Retrieve the original email with headers added by filters
|
|
operationId: getRawEmail
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
pattern: '^[a-z0-9-]+$'
|
|
description: Base32-encoded test ID (with hyphens)
|
|
responses:
|
|
'200':
|
|
description: Raw email retrieved successfully
|
|
content:
|
|
text/plain:
|
|
schema:
|
|
type: string
|
|
'404':
|
|
description: Email not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/report/{id}/reanalyze:
|
|
post:
|
|
tags:
|
|
- reports
|
|
summary: Reanalyze email and regenerate report
|
|
description: Re-run the analysis on the stored raw email to regenerate the report with the latest analyzer version. This is useful after analyzer improvements or bug fixes.
|
|
operationId: reanalyzeReport
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
pattern: '^[a-z0-9-]+$'
|
|
description: Base32-encoded test ID (with hyphens)
|
|
responses:
|
|
'200':
|
|
description: Report regenerated successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Report'
|
|
'404':
|
|
description: Email not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'500':
|
|
description: Internal server error during reanalysis
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/domain:
|
|
post:
|
|
tags:
|
|
- tests
|
|
summary: Test a domain's email configuration
|
|
description: Analyzes DNS records (MX, SPF, DMARC, BIMI) for a domain without requiring an actual email to be sent. Returns results immediately.
|
|
operationId: testDomain
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/DomainTestRequest'
|
|
responses:
|
|
'200':
|
|
description: Domain test completed successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/DomainTestResponse'
|
|
'400':
|
|
description: Invalid request
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'500':
|
|
description: Internal server error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/blacklist:
|
|
post:
|
|
tags:
|
|
- tests
|
|
summary: Check an IP address against DNS blacklists
|
|
description: Tests a single IP address (IPv4 or IPv6) against configured DNS-based blacklists (RBLs) without requiring an actual email to be sent. Returns results immediately.
|
|
operationId: checkBlacklist
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/BlacklistCheckRequest'
|
|
responses:
|
|
'200':
|
|
description: Blacklist check completed successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/BlacklistCheckResponse'
|
|
'400':
|
|
description: Invalid request
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'500':
|
|
description: Internal server error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/status:
|
|
get:
|
|
tags:
|
|
- health
|
|
summary: Service health check
|
|
description: Get service health status and component versions
|
|
operationId: getStatus
|
|
responses:
|
|
'200':
|
|
description: Service status
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Status'
|
|
|
|
components:
|
|
schemas:
|
|
Test:
|
|
type: object
|
|
required:
|
|
- id
|
|
- email
|
|
- status
|
|
properties:
|
|
id:
|
|
type: string
|
|
pattern: '^[a-z0-9-]+$'
|
|
description: Unique test identifier (base32-encoded with hyphens)
|
|
example: "krfwg4z-amrqw4z-zmorsw2-djmfzgk-3a"
|
|
email:
|
|
type: string
|
|
format: email
|
|
description: Unique test email address
|
|
example: "test-krfwg4z-amrqw4z-zmorsw2-djmfzgk-3a@example.com"
|
|
status:
|
|
type: string
|
|
enum: [pending, analyzed]
|
|
description: Current test status (pending = no report yet, analyzed = report available)
|
|
example: "analyzed"
|
|
|
|
TestResponse:
|
|
type: object
|
|
required:
|
|
- id
|
|
- email
|
|
- status
|
|
properties:
|
|
id:
|
|
type: string
|
|
pattern: '^[a-z0-9-]+$'
|
|
description: Unique test identifier (base32-encoded with hyphens)
|
|
example: "krfwg4z-amrqw4z-zmorsw2-djmfzgk-3a"
|
|
email:
|
|
type: string
|
|
format: email
|
|
example: "test-krfwg4z-amrqw4z-zmorsw2-djmfzgk-3a@example.com"
|
|
status:
|
|
type: string
|
|
enum: [pending]
|
|
example: "pending"
|
|
message:
|
|
type: string
|
|
example: "Send your test email to the address above"
|
|
|
|
Report:
|
|
type: object
|
|
required:
|
|
- id
|
|
- test_id
|
|
- score
|
|
- grade
|
|
- created_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
pattern: '^[a-z0-9-]+$'
|
|
description: Report identifier (base32-encoded with hyphens)
|
|
test_id:
|
|
type: string
|
|
pattern: '^[a-z0-9-]+$'
|
|
description: Associated test ID (base32-encoded with hyphens)
|
|
score:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: Overall deliverability score as percentage (0-100)
|
|
example: 85
|
|
grade:
|
|
type: string
|
|
enum: [A+, A, B, C, D, E, F]
|
|
description: Letter grade representation of the score (A+ is best, F is worst)
|
|
example: "A"
|
|
summary:
|
|
$ref: '#/components/schemas/ScoreSummary'
|
|
authentication:
|
|
$ref: '#/components/schemas/AuthenticationResults'
|
|
spamassassin:
|
|
$ref: '#/components/schemas/SpamAssassinResult'
|
|
rspamd:
|
|
$ref: '#/components/schemas/RspamdResult'
|
|
dns_results:
|
|
$ref: '#/components/schemas/DNSResults'
|
|
blacklists:
|
|
type: object
|
|
additionalProperties:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/BlacklistCheck'
|
|
description: Map of IP addresses to their blacklist check results (array of checks per IP)
|
|
example:
|
|
"192.0.2.1":
|
|
- rbl: "zen.spamhaus.org"
|
|
listed: false
|
|
- rbl: "bl.spamcop.net"
|
|
listed: false
|
|
content_analysis:
|
|
$ref: '#/components/schemas/ContentAnalysis'
|
|
header_analysis:
|
|
$ref: '#/components/schemas/HeaderAnalysis'
|
|
raw_headers:
|
|
type: string
|
|
description: Raw email headers
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
ScoreSummary:
|
|
type: object
|
|
required:
|
|
- dns_score
|
|
- dns_grade
|
|
- authentication_score
|
|
- authentication_grade
|
|
- spam_score
|
|
- spam_grade
|
|
- blacklist_score
|
|
- blacklist_grade
|
|
- header_score
|
|
- header_grade
|
|
- content_score
|
|
- content_grade
|
|
properties:
|
|
dns_score:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: DNS records score (in percentage)
|
|
example: 42
|
|
dns_grade:
|
|
type: string
|
|
enum: [A+, A, B, C, D, E, F]
|
|
description: Letter grade representation of the score (A+ is best, F is worst)
|
|
example: "A"
|
|
authentication_score:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: SPF/DKIM/DMARC score (in percentage)
|
|
example: 28
|
|
authentication_grade:
|
|
type: string
|
|
enum: [A+, A, B, C, D, E, F]
|
|
description: Letter grade representation of the score (A+ is best, F is worst)
|
|
example: "A"
|
|
spam_score:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: Spam filter score (SpamAssassin + rspamd combined, in percentage)
|
|
example: 15
|
|
spam_grade:
|
|
type: string
|
|
enum: [A+, A, B, C, D, E, F]
|
|
description: Letter grade representation of the score (A+ is best, F is worst)
|
|
example: "A"
|
|
blacklist_score:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: Blacklist check score (in percentage)
|
|
example: 20
|
|
blacklist_grade:
|
|
type: string
|
|
enum: [A+, A, B, C, D, E, F]
|
|
description: Letter grade representation of the score (A+ is best, F is worst)
|
|
example: "A"
|
|
header_score:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: Header quality score (in percentage)
|
|
example: 9
|
|
header_grade:
|
|
type: string
|
|
enum: [A+, A, B, C, D, E, F]
|
|
description: Letter grade representation of the score (A+ is best, F is worst)
|
|
example: "A"
|
|
content_score:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: Content quality score (in percentage)
|
|
example: 18
|
|
content_grade:
|
|
type: string
|
|
enum: [A+, A, B, C, D, E, F]
|
|
description: Letter grade representation of the score (A+ is best, F is worst)
|
|
example: "A"
|
|
|
|
ContentAnalysis:
|
|
type: object
|
|
properties:
|
|
has_html:
|
|
type: boolean
|
|
description: Whether email contains HTML part
|
|
example: true
|
|
has_plaintext:
|
|
type: boolean
|
|
description: Whether email contains plaintext part
|
|
example: true
|
|
html_issues:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/ContentIssue'
|
|
description: Issues found in HTML content
|
|
links:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/LinkCheck'
|
|
description: Analysis of links found in the email
|
|
images:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/ImageCheck'
|
|
description: Analysis of images in the email
|
|
text_to_image_ratio:
|
|
type: number
|
|
format: float
|
|
description: Ratio of text to images (higher is better)
|
|
example: 0.75
|
|
has_unsubscribe_link:
|
|
type: boolean
|
|
description: Whether email contains an unsubscribe link
|
|
example: true
|
|
unsubscribe_methods:
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum: [link, mailto, list-unsubscribe-header, one-click]
|
|
description: Available unsubscribe methods
|
|
example: ["link", "list-unsubscribe-header"]
|
|
|
|
ContentIssue:
|
|
type: object
|
|
required:
|
|
- type
|
|
- severity
|
|
- message
|
|
properties:
|
|
type:
|
|
type: string
|
|
enum: [broken_html, missing_alt, excessive_images, obfuscated_url, suspicious_link, dangerous_html]
|
|
description: Type of content issue
|
|
example: "missing_alt"
|
|
severity:
|
|
type: string
|
|
enum: [critical, high, medium, low, info]
|
|
description: Issue severity
|
|
example: "medium"
|
|
message:
|
|
type: string
|
|
description: Human-readable description
|
|
example: "3 images are missing alt attributes"
|
|
location:
|
|
type: string
|
|
description: Where the issue was found
|
|
example: "HTML body line 42"
|
|
advice:
|
|
type: string
|
|
description: How to fix this issue
|
|
example: "Add descriptive alt text to all images for better accessibility and deliverability"
|
|
|
|
LinkCheck:
|
|
type: object
|
|
required:
|
|
- url
|
|
- status
|
|
properties:
|
|
url:
|
|
type: string
|
|
format: uri
|
|
description: The URL found in the email
|
|
example: "https://example.com/page"
|
|
status:
|
|
type: string
|
|
enum: [valid, broken, suspicious, redirected, timeout]
|
|
description: Link validation status
|
|
example: "valid"
|
|
http_code:
|
|
type: integer
|
|
description: HTTP status code received
|
|
example: 200
|
|
redirect_chain:
|
|
type: array
|
|
items:
|
|
type: string
|
|
description: URLs in the redirect chain, if any
|
|
example: ["https://example.com", "https://www.example.com"]
|
|
is_shortened:
|
|
type: boolean
|
|
description: Whether this is a URL shortener
|
|
example: false
|
|
|
|
ImageCheck:
|
|
type: object
|
|
required:
|
|
- has_alt
|
|
properties:
|
|
src:
|
|
type: string
|
|
description: Image source URL or path
|
|
example: "https://example.com/logo.png"
|
|
has_alt:
|
|
type: boolean
|
|
description: Whether image has alt attribute
|
|
example: true
|
|
alt_text:
|
|
type: string
|
|
description: Alt text content
|
|
example: "Company Logo"
|
|
is_tracking_pixel:
|
|
type: boolean
|
|
description: Whether this appears to be a tracking pixel (1x1 image)
|
|
example: false
|
|
|
|
HeaderAnalysis:
|
|
type: object
|
|
properties:
|
|
has_mime_structure:
|
|
type: boolean
|
|
description: Whether body has a MIME structure
|
|
example: true
|
|
headers:
|
|
type: object
|
|
additionalProperties:
|
|
$ref: '#/components/schemas/HeaderCheck'
|
|
description: Map of header names to their check results (e.g., "from", "to", "dkim-signature")
|
|
example:
|
|
from:
|
|
present: true
|
|
value: "sender@example.com"
|
|
valid: true
|
|
importance: "required"
|
|
date:
|
|
present: true
|
|
value: "Mon, 1 Jan 2024 12:00:00 +0000"
|
|
valid: true
|
|
importance: "required"
|
|
received_chain:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/ReceivedHop'
|
|
description: Chain of Received headers showing email path
|
|
domain_alignment:
|
|
$ref: '#/components/schemas/DomainAlignment'
|
|
issues:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/HeaderIssue'
|
|
description: Issues found in headers
|
|
|
|
HeaderCheck:
|
|
type: object
|
|
required:
|
|
- present
|
|
properties:
|
|
present:
|
|
type: boolean
|
|
description: Whether the header is present
|
|
example: true
|
|
value:
|
|
type: string
|
|
description: Header value
|
|
example: "sender@example.com"
|
|
valid:
|
|
type: boolean
|
|
description: Whether the value is valid/well-formed
|
|
example: true
|
|
importance:
|
|
type: string
|
|
enum: [required, recommended, optional, newsletter]
|
|
description: How important this header is for deliverability
|
|
example: "required"
|
|
issues:
|
|
type: array
|
|
items:
|
|
type: string
|
|
description: Any issues with this header
|
|
example: ["Invalid date format"]
|
|
|
|
ReceivedHop:
|
|
type: object
|
|
properties:
|
|
from:
|
|
type: string
|
|
description: Sending server hostname
|
|
example: "mail.example.com"
|
|
by:
|
|
type: string
|
|
description: Receiving server hostname
|
|
example: "mx.receiver.com"
|
|
with:
|
|
type: string
|
|
description: Protocol used
|
|
example: "ESMTPS"
|
|
id:
|
|
type: string
|
|
description: Message ID at this hop
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
description: When this hop occurred
|
|
ip:
|
|
type: string
|
|
description: IP address of the sending server (IPv4 or IPv6)
|
|
example: "192.0.2.1"
|
|
reverse:
|
|
type: string
|
|
description: Reverse DNS (PTR record) for the IP address
|
|
example: "mail.example.com"
|
|
|
|
DKIMDomainInfo:
|
|
type: object
|
|
required:
|
|
- domain
|
|
- org_domain
|
|
properties:
|
|
domain:
|
|
type: string
|
|
description: DKIM signature domain
|
|
example: "mail.example.com"
|
|
org_domain:
|
|
type: string
|
|
description: Organizational domain extracted from DKIM domain (using Public Suffix List)
|
|
example: "example.com"
|
|
|
|
DomainAlignment:
|
|
type: object
|
|
properties:
|
|
from_domain:
|
|
type: string
|
|
description: Domain from From header
|
|
example: "example.com"
|
|
from_org_domain:
|
|
type: string
|
|
description: Organizational domain extracted from From header (using Public Suffix List)
|
|
example: "example.com"
|
|
return_path_domain:
|
|
type: string
|
|
description: Domain from Return-Path header
|
|
example: "example.com"
|
|
return_path_org_domain:
|
|
type: string
|
|
description: Organizational domain extracted from Return-Path header (using Public Suffix List)
|
|
example: "example.com"
|
|
dkim_domains:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/DKIMDomainInfo'
|
|
description: Domains from DKIM signatures with their organizational domains
|
|
aligned:
|
|
type: boolean
|
|
description: Whether all domains align (strict alignment - exact match)
|
|
example: true
|
|
relaxed_aligned:
|
|
type: boolean
|
|
description: Whether domains satisfy relaxed alignment (organizational domain match)
|
|
example: true
|
|
issues:
|
|
type: array
|
|
items:
|
|
type: string
|
|
description: Alignment issues
|
|
example: ["Return-Path domain does not match From domain"]
|
|
|
|
HeaderIssue:
|
|
type: object
|
|
required:
|
|
- header
|
|
- severity
|
|
- message
|
|
properties:
|
|
header:
|
|
type: string
|
|
description: Header name
|
|
example: "Date"
|
|
severity:
|
|
type: string
|
|
enum: [critical, high, medium, low, info]
|
|
description: Issue severity
|
|
example: "medium"
|
|
message:
|
|
type: string
|
|
description: Human-readable description
|
|
example: "Date header is in the future"
|
|
advice:
|
|
type: string
|
|
description: How to fix this issue
|
|
example: "Ensure your mail server clock is synchronized with NTP"
|
|
|
|
AuthenticationResults:
|
|
type: object
|
|
properties:
|
|
spf:
|
|
$ref: '#/components/schemas/AuthResult'
|
|
dkim:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AuthResult'
|
|
dmarc:
|
|
$ref: '#/components/schemas/AuthResult'
|
|
bimi:
|
|
$ref: '#/components/schemas/AuthResult'
|
|
arc:
|
|
$ref: '#/components/schemas/ARCResult'
|
|
iprev:
|
|
$ref: '#/components/schemas/IPRevResult'
|
|
x_google_dkim:
|
|
$ref: '#/components/schemas/AuthResult'
|
|
description: Google-specific DKIM authentication result (x-google-dkim)
|
|
x_aligned_from:
|
|
$ref: '#/components/schemas/AuthResult'
|
|
description: X-Aligned-From authentication result (checks address alignment)
|
|
|
|
AuthResult:
|
|
type: object
|
|
required:
|
|
- result
|
|
properties:
|
|
result:
|
|
type: string
|
|
enum: [pass, fail, invalid, missing, none, neutral, softfail, temperror, permerror, declined, domain_pass, orgdomain_pass]
|
|
description: Authentication result
|
|
example: "pass"
|
|
domain:
|
|
type: string
|
|
description: Domain being authenticated
|
|
example: "example.com"
|
|
selector:
|
|
type: string
|
|
description: DKIM selector (for DKIM only)
|
|
example: "default"
|
|
details:
|
|
type: string
|
|
description: Additional details about the result
|
|
|
|
ARCResult:
|
|
type: object
|
|
required:
|
|
- result
|
|
properties:
|
|
result:
|
|
type: string
|
|
enum: [pass, fail, none]
|
|
description: Overall ARC chain validation result
|
|
example: "pass"
|
|
chain_valid:
|
|
type: boolean
|
|
description: Whether the ARC chain signatures are valid
|
|
example: true
|
|
chain_length:
|
|
type: integer
|
|
description: Number of ARC sets in the chain
|
|
example: 2
|
|
details:
|
|
type: string
|
|
description: Additional details about ARC validation
|
|
example: "ARC chain valid with 2 intermediaries"
|
|
|
|
IPRevResult:
|
|
type: object
|
|
required:
|
|
- result
|
|
properties:
|
|
result:
|
|
type: string
|
|
enum: [pass, fail, temperror, permerror]
|
|
description: IP reverse DNS lookup result
|
|
example: "pass"
|
|
ip:
|
|
type: string
|
|
description: IP address that was checked
|
|
example: "195.110.101.58"
|
|
hostname:
|
|
type: string
|
|
description: Hostname from reverse DNS lookup (PTR record)
|
|
example: "authsmtp74.register.it"
|
|
details:
|
|
type: string
|
|
description: Additional details about the IP reverse lookup
|
|
example: "smtp.remote-ip=195.110.101.58 (authsmtp74.register.it)"
|
|
|
|
SpamAssassinResult:
|
|
type: object
|
|
required:
|
|
- score
|
|
- required_score
|
|
- is_spam
|
|
- test_details
|
|
properties:
|
|
deliverability_score:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: SpamAssassin deliverability score (0-100, higher is better)
|
|
example: 80
|
|
deliverability_grade:
|
|
type: string
|
|
enum: [A+, A, B, C, D, E, F]
|
|
description: Letter grade for SpamAssassin deliverability score
|
|
example: "B"
|
|
version:
|
|
type: string
|
|
description: SpamAssassin version
|
|
example: "SpamAssassin 4.0.1"
|
|
score:
|
|
type: number
|
|
format: float
|
|
description: SpamAssassin spam score
|
|
example: 2.3
|
|
required_score:
|
|
type: number
|
|
format: float
|
|
description: Threshold for spam classification
|
|
example: 5.0
|
|
is_spam:
|
|
type: boolean
|
|
description: Whether message is classified as spam
|
|
example: false
|
|
tests:
|
|
type: array
|
|
items:
|
|
type: string
|
|
description: List of triggered SpamAssassin tests
|
|
example: ["BAYES_00", "DKIM_SIGNED"]
|
|
test_details:
|
|
type: object
|
|
additionalProperties:
|
|
$ref: '#/components/schemas/SpamTestDetail'
|
|
description: Map of test names to their detailed results
|
|
example:
|
|
BAYES_00:
|
|
name: "BAYES_00"
|
|
score: -1.9
|
|
description: "Bayes spam probability is 0 to 1%"
|
|
DKIM_SIGNED:
|
|
name: "DKIM_SIGNED"
|
|
score: 0.1
|
|
description: "Message has a DKIM or DK signature, not necessarily valid"
|
|
report:
|
|
type: string
|
|
description: Full SpamAssassin report
|
|
|
|
SpamTestDetail:
|
|
type: object
|
|
required:
|
|
- name
|
|
- score
|
|
properties:
|
|
name:
|
|
type: string
|
|
description: Test name
|
|
example: "BAYES_00"
|
|
score:
|
|
type: number
|
|
format: float
|
|
description: Score contribution of this test
|
|
example: -1.9
|
|
description:
|
|
type: string
|
|
description: Human-readable description of what this test checks
|
|
example: "Bayes spam probability is 0 to 1%"
|
|
|
|
RspamdResult:
|
|
type: object
|
|
required:
|
|
- score
|
|
- threshold
|
|
- is_spam
|
|
- symbols
|
|
properties:
|
|
deliverability_score:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: rspamd deliverability score (0-100, higher is better)
|
|
example: 85
|
|
deliverability_grade:
|
|
type: string
|
|
enum: [A+, A, B, C, D, E, F]
|
|
description: Letter grade for rspamd deliverability score
|
|
example: "A"
|
|
score:
|
|
type: number
|
|
format: float
|
|
description: rspamd spam score
|
|
example: -3.91
|
|
threshold:
|
|
type: number
|
|
format: float
|
|
description: Score threshold for spam classification
|
|
example: 15.0
|
|
action:
|
|
type: string
|
|
description: rspamd action (no action, add header, rewrite subject, soft reject, reject)
|
|
example: "no action"
|
|
is_spam:
|
|
type: boolean
|
|
description: Whether message is classified as spam (action is reject or soft reject)
|
|
example: false
|
|
server:
|
|
type: string
|
|
description: rspamd server that processed the message
|
|
example: "rspamd.example.com"
|
|
symbols:
|
|
type: object
|
|
additionalProperties:
|
|
$ref: '#/components/schemas/RspamdSymbol'
|
|
description: Map of triggered rspamd symbols to their details
|
|
example:
|
|
BAYES_HAM:
|
|
name: "BAYES_HAM"
|
|
score: -1.9
|
|
params: "0.02"
|
|
|
|
RspamdSymbol:
|
|
type: object
|
|
required:
|
|
- name
|
|
- score
|
|
properties:
|
|
name:
|
|
type: string
|
|
description: Symbol name
|
|
example: "BAYES_HAM"
|
|
score:
|
|
type: number
|
|
format: float
|
|
description: Score contribution of this symbol
|
|
example: -1.9
|
|
params:
|
|
type: string
|
|
description: Symbol parameters or options
|
|
example: "0.02"
|
|
|
|
DNSResults:
|
|
type: object
|
|
required:
|
|
- from_domain
|
|
properties:
|
|
from_domain:
|
|
type: string
|
|
description: From Domain name
|
|
example: "example.com"
|
|
rp_domain:
|
|
type: string
|
|
description: Return Path Domain name
|
|
example: "example.com"
|
|
from_mx_records:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/MXRecord'
|
|
description: MX records for the From domain
|
|
rp_mx_records:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/MXRecord'
|
|
description: MX records for the Return-Path domain
|
|
spf_records:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/SPFRecord'
|
|
description: SPF records found (includes resolved include directives)
|
|
dkim_records:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/DKIMRecord'
|
|
description: DKIM records found
|
|
dmarc_record:
|
|
$ref: '#/components/schemas/DMARCRecord'
|
|
bimi_record:
|
|
$ref: '#/components/schemas/BIMIRecord'
|
|
ptr_records:
|
|
type: array
|
|
items:
|
|
type: string
|
|
description: PTR (reverse DNS) records for the sender IP address
|
|
example: ["mail.example.com", "smtp.example.com"]
|
|
ptr_forward_records:
|
|
type: array
|
|
items:
|
|
type: string
|
|
description: A or AAAA records resolved from the PTR hostnames (forward confirmation)
|
|
example: ["192.0.2.1", "2001:db8::1"]
|
|
errors:
|
|
type: array
|
|
items:
|
|
type: string
|
|
description: DNS lookup errors
|
|
|
|
MXRecord:
|
|
type: object
|
|
required:
|
|
- host
|
|
- priority
|
|
- valid
|
|
properties:
|
|
host:
|
|
type: string
|
|
description: MX hostname
|
|
example: "mail.example.com"
|
|
priority:
|
|
type: integer
|
|
format: uint16
|
|
description: MX priority (lower is higher priority)
|
|
example: 10
|
|
valid:
|
|
type: boolean
|
|
description: Whether the MX record is valid
|
|
example: true
|
|
error:
|
|
type: string
|
|
description: Error message if validation failed
|
|
example: "Failed to lookup MX records"
|
|
|
|
SPFRecord:
|
|
type: object
|
|
required:
|
|
- valid
|
|
properties:
|
|
domain:
|
|
type: string
|
|
description: Domain this SPF record belongs to
|
|
example: "example.com"
|
|
record:
|
|
type: string
|
|
description: SPF record content
|
|
example: "v=spf1 include:_spf.example.com ~all"
|
|
valid:
|
|
type: boolean
|
|
description: Whether the SPF record is valid
|
|
example: true
|
|
all_qualifier:
|
|
type: string
|
|
enum: ["+", "-", "~", "?"]
|
|
description: "Qualifier for the 'all' mechanism: + (pass), - (fail), ~ (softfail), ? (neutral)"
|
|
example: "~"
|
|
error:
|
|
type: string
|
|
description: Error message if validation failed
|
|
example: "No SPF record found"
|
|
|
|
DKIMRecord:
|
|
type: object
|
|
required:
|
|
- selector
|
|
- domain
|
|
- valid
|
|
properties:
|
|
selector:
|
|
type: string
|
|
description: DKIM selector
|
|
example: "default"
|
|
domain:
|
|
type: string
|
|
description: Domain name
|
|
example: "example.com"
|
|
record:
|
|
type: string
|
|
description: DKIM record content
|
|
example: "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA..."
|
|
valid:
|
|
type: boolean
|
|
description: Whether the DKIM record is valid
|
|
example: true
|
|
error:
|
|
type: string
|
|
description: Error message if validation failed
|
|
example: "No DKIM record found"
|
|
|
|
DMARCRecord:
|
|
type: object
|
|
required:
|
|
- valid
|
|
properties:
|
|
record:
|
|
type: string
|
|
description: DMARC record content
|
|
example: "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"
|
|
policy:
|
|
type: string
|
|
enum: [none, quarantine, reject, unknown]
|
|
description: DMARC policy
|
|
example: "quarantine"
|
|
subdomain_policy:
|
|
type: string
|
|
enum: [none, quarantine, reject, unknown]
|
|
description: DMARC subdomain policy (sp tag) - policy for subdomains if different from main policy
|
|
example: "quarantine"
|
|
percentage:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: Percentage of messages subjected to filtering (pct tag, default 100)
|
|
example: 100
|
|
spf_alignment:
|
|
type: string
|
|
enum: [relaxed, strict]
|
|
description: SPF alignment mode (aspf tag)
|
|
example: "relaxed"
|
|
dkim_alignment:
|
|
type: string
|
|
enum: [relaxed, strict]
|
|
description: DKIM alignment mode (adkim tag)
|
|
example: "relaxed"
|
|
valid:
|
|
type: boolean
|
|
description: Whether the DMARC record is valid
|
|
example: true
|
|
error:
|
|
type: string
|
|
description: Error message if validation failed
|
|
example: "No DMARC record found"
|
|
|
|
BIMIRecord:
|
|
type: object
|
|
required:
|
|
- selector
|
|
- domain
|
|
- valid
|
|
properties:
|
|
selector:
|
|
type: string
|
|
description: BIMI selector
|
|
example: "default"
|
|
domain:
|
|
type: string
|
|
description: Domain name
|
|
example: "example.com"
|
|
record:
|
|
type: string
|
|
description: BIMI record content
|
|
example: "v=BIMI1; l=https://example.com/logo.svg"
|
|
logo_url:
|
|
type: string
|
|
format: uri
|
|
description: URL to the brand logo (SVG)
|
|
example: "https://example.com/logo.svg"
|
|
vmc_url:
|
|
type: string
|
|
format: uri
|
|
description: URL to Verified Mark Certificate (optional)
|
|
example: "https://example.com/vmc.pem"
|
|
valid:
|
|
type: boolean
|
|
description: Whether the BIMI record is valid
|
|
example: true
|
|
error:
|
|
type: string
|
|
description: Error message if validation failed
|
|
example: "No BIMI record found"
|
|
|
|
BlacklistCheck:
|
|
type: object
|
|
required:
|
|
- rbl
|
|
- listed
|
|
properties:
|
|
rbl:
|
|
type: string
|
|
description: RBL/DNSBL name
|
|
example: "zen.spamhaus.org"
|
|
listed:
|
|
type: boolean
|
|
description: Whether IP is listed
|
|
example: false
|
|
response:
|
|
type: string
|
|
description: RBL response code or message
|
|
example: "127.0.0.2"
|
|
error:
|
|
type: string
|
|
description: RBL error if any
|
|
|
|
Status:
|
|
type: object
|
|
required:
|
|
- status
|
|
- version
|
|
properties:
|
|
status:
|
|
type: string
|
|
enum: [healthy, degraded, unhealthy]
|
|
description: Overall service status
|
|
example: "healthy"
|
|
version:
|
|
type: string
|
|
description: Service version
|
|
example: "0.1.0-dev"
|
|
components:
|
|
type: object
|
|
properties:
|
|
database:
|
|
type: string
|
|
enum: [up, down]
|
|
example: "up"
|
|
mta:
|
|
type: string
|
|
enum: [up, down]
|
|
example: "up"
|
|
uptime:
|
|
type: integer
|
|
description: Service uptime in seconds
|
|
example: 3600
|
|
|
|
Error:
|
|
type: object
|
|
required:
|
|
- error
|
|
- message
|
|
properties:
|
|
error:
|
|
type: string
|
|
description: Error code
|
|
example: "not_found"
|
|
message:
|
|
type: string
|
|
description: Human-readable error message
|
|
example: "Test not found"
|
|
details:
|
|
type: string
|
|
description: Additional error details
|
|
|
|
DomainTestRequest:
|
|
type: object
|
|
required:
|
|
- domain
|
|
properties:
|
|
domain:
|
|
type: string
|
|
pattern: '^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$'
|
|
description: Domain name to test (e.g., example.com)
|
|
example: "example.com"
|
|
|
|
DomainTestResponse:
|
|
type: object
|
|
required:
|
|
- domain
|
|
- score
|
|
- grade
|
|
- dns_results
|
|
properties:
|
|
domain:
|
|
type: string
|
|
description: The tested domain name
|
|
example: "example.com"
|
|
score:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: Overall domain configuration score (0-100)
|
|
example: 85
|
|
grade:
|
|
type: string
|
|
enum: [A+, A, B, C, D, E, F]
|
|
description: Letter grade representation of the score
|
|
example: "A"
|
|
dns_results:
|
|
$ref: '#/components/schemas/DNSResults'
|
|
|
|
BlacklistCheckRequest:
|
|
type: object
|
|
required:
|
|
- ip
|
|
properties:
|
|
ip:
|
|
type: string
|
|
description: IPv4 or IPv6 address to check against blacklists
|
|
example: "192.0.2.1"
|
|
pattern: '^([0-9]{1,3}\.){3}[0-9]{1,3}$|^([0-9a-fA-F]{0,4}:){7}[0-9a-fA-F]{0,4}$|^::([0-9a-fA-F]{0,4}:){0,6}[0-9a-fA-F]{0,4}$|^([0-9a-fA-F]{0,4}:){1,6}:([0-9a-fA-F]{0,4}:){0,5}[0-9a-fA-F]{0,4}$'
|
|
|
|
BlacklistCheckResponse:
|
|
type: object
|
|
required:
|
|
- ip
|
|
- checks
|
|
- listed_count
|
|
- score
|
|
- grade
|
|
properties:
|
|
ip:
|
|
type: string
|
|
description: The IP address that was checked
|
|
example: "192.0.2.1"
|
|
checks:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/BlacklistCheck'
|
|
description: List of blacklist check results
|
|
listed_count:
|
|
type: integer
|
|
description: Number of blacklists that have this IP listed
|
|
example: 0
|
|
score:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: Blacklist score (0-100, higher is better)
|
|
example: 100
|
|
grade:
|
|
type: string
|
|
enum: [A+, A, B, C, D, E, F]
|
|
description: Letter grade representation of the score
|
|
example: "A+"
|