PHPackages                             cbowofrivia/dmarc-record-builder - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Mail &amp; Notifications](/categories/mail)
4. /
5. cbowofrivia/dmarc-record-builder

ActiveLibrary[Mail &amp; Notifications](/categories/mail)

cbowofrivia/dmarc-record-builder
================================

A lean package that makes creating DMARC records user friendly

v3.0.1(1mo ago)6119.2k↓46.8%1MITPHPPHP ^8.2CI passing

Since May 6Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/cbowofrivia/dmarc-record-builder)[ Packagist](https://packagist.org/packages/cbowofrivia/dmarc-record-builder)[ Docs](https://github.com/cbowofrivia/dmarc-record-builder)[ RSS](/packages/cbowofrivia-dmarc-record-builder/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (7)Dependencies (11)Versions (18)Used By (0)

DMARC Record Builder
====================

[](#dmarc-record-builder)

[![Latest Version on Packagist](https://camo.githubusercontent.com/d4895a765c91f68d2887cd88aa35b744a65a5c2189922920f8dc82674c820a02/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f63626f776f6672697669612f646d6172632d7265636f72642d6275696c6465722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/cbowofrivia/dmarc-record-builder)[![Tests](https://github.com/cbowofrivia/dmarc-record-builder/actions/workflows/run-tests.yml/badge.svg?branch=main)](https://github.com/cbowofrivia/dmarc-record-builder/actions/workflows/run-tests.yml)[![codecov](https://camo.githubusercontent.com/d5dc1615c130edbf0dac1720d5bbdc105190fb3702d391294e639a42deb13de4/68747470733a2f2f636f6465636f762e696f2f67682f63626f776f6672697669612f646d6172632d7265636f72642d6275696c6465722f67726170682f62616467652e737667)](https://codecov.io/gh/cbowofrivia/dmarc-record-builder)[![Total Downloads](https://camo.githubusercontent.com/70f3bc8e675f4a40ca2d31d064385828b5b3019bd8719aa571177c53143284d4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f63626f776f6672697669612f646d6172632d7265636f72642d6275696c6465722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/cbowofrivia/dmarc-record-builder)

A PHP package for building and parsing DMARC DNS records with a fluent, human-friendly API. Accepts readable values (`'relaxed'`, `'strict'`, `'reject'`) and outputs correctly formatted DMARC strings.

Requirements
------------

[](#requirements)

- PHP 8.2 or higher

Installation
------------

[](#installation)

```
composer require cbowofrivia/dmarc-record-builder
```

Quick Start
-----------

[](#quick-start)

```
use CbowOfRivia\DmarcRecordBuilder\DmarcRecord;

$record = (string) (new DmarcRecord())
    ->policy('reject')
    ->rua('mailto:dmarc@example.com');

// v=DMARC1; p=reject; rua=mailto:dmarc@example.com
```

Building a Record
-----------------

[](#building-a-record)

### Fluent API

[](#fluent-api)

All setter methods return `$this`, so calls can be chained:

```
$record = new DmarcRecord();

$record->policy('reject')
    ->subdomainPolicy('quarantine')
    ->pct(100)
    ->rua('mailto:dmarc@example.com')
    ->ruf('mailto:dmarc-forensic@example.com')
    ->adkim('relaxed')
    ->aspf('strict')
    ->reporting(['dkim', 'spf'])
    ->interval(86400)
    ->nonExistentSubdomainPolicy('reject')
    ->publicSuffixDomainPolicy('y')
    ->testingMode('n');

echo $record;
// v=DMARC1; p=reject; sp=quarantine; pct=100; rua=mailto:dmarc@example.com; ruf=mailto:dmarc-forensic@example.com; adkim=r; aspf=s; fo=d:s; ri=86400; np=reject; psd=y; t=n
```

### Constructor

[](#constructor)

All parameters are optional. The constructor accepts the same values as the fluent setters:

```
$record = new DmarcRecord(
    version: 'DMARC1',
    policy: 'reject',
    subdomain_policy: 'quarantine',
    pct: 100,
    rua: 'mailto:dmarc@example.com',
    ruf: 'mailto:dmarc-forensic@example.com',
    adkim: 'relaxed',
    aspf: 'strict',
    reporting: ['dkim', 'spf'],
    interval: 86400,
    np: 'reject',
    psd: 'y',
    t: 'n',
);
```

### Static Factory

[](#static-factory)

`DmarcRecord::create()` is a convenience wrapper around the constructor, useful when you want to build and cast in one expression:

```
$record = (string) DmarcRecord::create(
    policy: 'quarantine',
    pct: 20,
    rua: 'mailto:dmarc@example.com',
);

// v=DMARC1; p=quarantine; pct=20; rua=mailto:dmarc@example.com
```

Parsing an Existing Record
--------------------------

[](#parsing-an-existing-record)

Pass a raw DMARC TXT record string to `DmarcRecord::parse()` to get a populated `DmarcRecord` object. This is useful for reading and modifying existing records.

```
$record = DmarcRecord::parse('v=DMARC1; p=quarantine; adkim=r; aspf=s; fo=d:s');

$record->policy;      // 'quarantine'
$record->adkim;       // 'relaxed'  (translated from 'r')
$record->aspf;        // 'strict'   (translated from 's')
$record->reporting;   // ['dkim', 'spf']  (translated from 'fo=d:s')
```

After parsing, you can modify the record and re-cast it to a string:

```
$record = DmarcRecord::parse('v=DMARC1; p=none; rua=mailto:dmarc@example.com');
$record->policy('reject');

echo $record;
// v=DMARC1; p=reject; rua=mailto:dmarc@example.com
```

`parse()` requires both `v` and `p` tags to be present and will throw an `InvalidArgumentException` if either is missing. Unknown tags are silently ignored.

Tag Reference
-------------

[](#tag-reference)

MethodDMARC TagAccepted ValuesDefault`version()``v``'DMARC1'``'DMARC1'``policy()``p``'none'`, `'quarantine'`, `'reject'``'none'``subdomainPolicy()``sp``'none'`, `'quarantine'`, `'reject'``null``pct()``pct`Integer`null``rua()``rua``'mailto:...'``null``ruf()``ruf``'mailto:...'``null``adkim()``adkim``'relaxed'`, `'strict'``null``aspf()``aspf``'relaxed'`, `'strict'``null``reporting()``fo``'all'`, `'any'`, `'dkim'`, `'spf'``[]``interval()``ri`Integer (seconds)`null``nonExistentSubdomainPolicy()``np``'none'`, `'quarantine'`, `'reject'``null``publicSuffixDomainPolicy()``psd``'y'`, `'n'`, `'u'``null``testingMode()``t``'y'`, `'n'``null`Tags with a `null` value are omitted from the output string. Only `v` and `p` are always emitted.

### Tag Details

[](#tag-details)

#### `policy()` / `subdomainPolicy()` / `nonExistentSubdomainPolicy()`

[](#policy--subdomainpolicy--nonexistentsubdomainpolicy)

Controls how the receiving mail server handles messages that fail DMARC checks.

- `'none'` — take no action; useful during monitoring
- `'quarantine'` — send to spam/junk
- `'reject'` — reject the message outright

`subdomainPolicy()` (`sp`) overrides `policy()` for subdomains. If omitted, subdomains inherit the main policy.

`nonExistentSubdomainPolicy()` (`np`) applies to non-existent subdomains (RFC 9091 / DMARCbis). Takes precedence over both `policy()` and `subdomainPolicy()` for those domains.

#### `pct()`

[](#pct)

The percentage of messages the policy is applied to (1–100). Useful for gradual rollout. Omit to apply the policy to all messages.

#### `rua()` / `ruf()`

[](#rua--ruf)

URIs for receiving DMARC reports. Must be prefixed with `mailto:`.

- `rua` — aggregate reports (daily summaries from receivers)
- `ruf` — forensic/failure reports (per-message failure details; not all receivers send these)

```
->rua('mailto:dmarc@example.com')
->ruf('mailto:dmarc-forensic@example.com')
```

#### `adkim()` / `aspf()`

[](#adkim--aspf)

Alignment mode for DKIM and SPF respectively.

- `'relaxed'` — the organisational domain must match (e.g. `mail.example.com` aligns with `example.com`)
- `'strict'` — the domains must match exactly

Omitting either defaults to relaxed alignment per the RFC.

#### `reporting()`

[](#reporting)

Specifies which failure conditions trigger a forensic report. Accepts a string or an array of options:

Value`fo` tagMeaning`'all'``fo=0`Report if all mechanisms fail`'any'``fo=1`Report if any mechanism fails`'dkim'``fo=d`Report if DKIM fails`'spf'``fo=s`Report if SPF failsMultiple values produce a colon-separated `fo` tag:

```
->reporting(['dkim', 'spf'])
// fo=d:s

->reporting(['any'])
// fo=1
```

Duplicate values are silently deduplicated. `'all'` and `'any'` are mutually exclusive — passing both throws an `InvalidArgumentException`.

#### `interval()`

[](#interval)

How often (in seconds) receivers should send aggregate reports. The RFC default is 86400 (24 hours).

#### `publicSuffixDomainPolicy()`

[](#publicsuffixdomainpolicy)

Controls DMARC policy application at public suffix domains (DMARCbis extension).

- `'y'` — apply DMARC policy to this public suffix domain
- `'n'` — do not apply policy to this public suffix domain
- `'u'` — undefined / unknown

#### `testingMode()`

[](#testingmode)

When set to `'y'`, signals that DMARC is in testing mode. Receivers should not apply policy actions but may still send reports.

Validation
----------

[](#validation)

The package validates inputs on each setter call. Passing an invalid value throws an `InvalidArgumentException` from `webmozart/assert`.

```
// Throws: Expected one of: "none", "quarantine", "reject", NULL. Got: "monitor"
$record->policy('monitor');

// Throws: rua mailto address should start with "mailto:"
$record->rua('dmarc@example.com');

// Throws: Expected one of: "relaxed", "strict", NULL. Got: "loose"
$record->adkim('loose');

// Throws: Reporting options "all" (0) and "any" (1) are mutually exclusive.
$record->reporting(['all', 'any']);
```

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Credits
-------

[](#credits)

- [Charles Bowen](https://github.com/cbowofrivia)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

55

—

FairBetter than 98% of packages

Maintenance88

Actively maintained with recent releases

Popularity36

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity69

Established project with proven stability

 Bus Factor1

Top contributor holds 67% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~235 days

Recently: every ~353 days

Total

7

Last Release

59d ago

Major Versions

1.0.1 → 2.0.02024-04-20

2.1.0 → v3.0.02026-03-20

PHP version history (2 changes)1.0.0PHP ^8.0

2.0.0PHP ^8.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/33219142?v=4)[Charles R Bowen](/maintainers/cbowofrivia)[@cbowofrivia](https://github.com/cbowofrivia)

---

Top Contributors

[![cbowofrivia](https://avatars.githubusercontent.com/u/33219142?v=4)](https://github.com/cbowofrivia "cbowofrivia (65 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (21 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (9 commits)")[![jmalinens](https://avatars.githubusercontent.com/u/569039?v=4)](https://github.com/jmalinens "jmalinens (2 commits)")

---

Tags

dmarcemailphpsecuritydmarccbowofriviadmarc-record-builder

###  Code Quality

TestsPest

Static AnalysisRector

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/cbowofrivia-dmarc-record-builder/health.svg)

```
[![Health](https://phpackages.com/badges/cbowofrivia-dmarc-record-builder/health.svg)](https://phpackages.com/packages/cbowofrivia-dmarc-record-builder)
```

###  Alternatives

[mailgun/mailgun-php

The Mailgun SDK provides methods for all API functions.

1.1k28.9M168](/packages/mailgun-mailgun-php)[directorytree/imapengine

A fully-featured IMAP library -- without the PHP extension

531175.4k4](/packages/directorytree-imapengine)[illuminate/mail

The Illuminate Mail package.

5910.1M391](/packages/illuminate-mail)[illuminate/notifications

The Illuminate Notifications package.

483.0M967](/packages/illuminate-notifications)[sylius/mailer-bundle

Mailers and e-mail template management for Symfony projects.

728.1M77](/packages/sylius-mailer-bundle)[sylius/mailer

Mails management and sending abstraction.

14164.2k4](/packages/sylius-mailer)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
