Compare commits

..

195 Commits

Author SHA1 Message Date
Ralph Slooten
dc3e7e701f Merge branch 'release/v1.29.2' 2026-02-25 12:28:45 +13:00
Ralph Slooten
f1d0bcda90 Release v1.29.2 2026-02-25 12:28:44 +13:00
Ralph Slooten
4f651e4f14 Chore: Update caniemail test database 2026-02-25 12:10:33 +13:00
Ralph Slooten
c3819ca26d Chore: Update node dependencies 2026-02-25 12:09:34 +13:00
Ralph Slooten
4febeb1acd Chore: Update Go dependencies 2026-02-25 12:07:32 +13:00
Ralph Slooten
10ad4df8cc Security: Prevent Server-Side Request Forgery (SSRF) via Link Check API ([GHSA-mpf7-p9x7-96r3](https://github.com/axllent/mailpit/security/advisories/GHSA-mpf7-p9x7-96r3))
By default all internal HTTP requests are now blocked, unless mailpit is started with the `--allow-internal-http-requests` flag (env  `MP_ALLOW_INTERNAL_HTTP_REQUESTS=true`).
2026-02-24 14:22:02 +13:00
Ralph Slooten
632113fcc5 Fix: Include 8BITMIME in SMTPD EHLO response (#648) 2026-02-24 11:25:19 +13:00
Ralph Slooten
08ed46fc46 Use const instead of let 2026-02-21 22:43:51 +13:00
Ralph Slooten
6927c2b73b Chore: Upgrade eslint JavaScript linting 2026-02-21 22:43:34 +13:00
Matthew Spahr
ac81da5ae0 Fix: Update install instructions when setting INSTALL_PATH 2026-02-17 20:51:14 +13:00
Ralph Slooten
f1d55e4e39 Release v1.29.1 2026-02-13 20:57:09 +13:00
Ralph Slooten
b622252411 Merge tag 'v1.29.1' into develop
Release v1.29.1
2026-02-13 20:47:03 +13:00
Ralph Slooten
5527379475 Merge branch 'release/v1.29.1' 2026-02-13 20:46:59 +13:00
Ralph Slooten
1d87f1164e Chore: Update node dependencies 2026-02-13 20:44:34 +13:00
Ralph Slooten
b4ca68eb48 Chore: Update Go dependencies 2026-02-13 20:38:19 +13:00
dependabot[bot]
971ae95a67 Chore: Bump axios from 1.13.4 to 1.13.5
Bumps [axios](https://github.com/axios/axios) from 1.13.4 to 1.13.5.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.13.4...v1.13.5)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.13.5
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 18:27:21 +13:00
Ralph Slooten
c8caa29e24 Fix: Enable "Mark all read" button (Inbox) when new message is received 2026-02-09 15:38:11 +13:00
Ralph Slooten
7d314d2b50 Chore: Add CORS error logging and update error messages for failed CORS requests 2026-02-08 11:19:54 +13:00
Ralph Slooten
9d2f30787a Fix spelling 2026-02-08 11:17:17 +13:00
Ralph Slooten
b9d071db81 Update contributing document 2026-02-05 17:05:12 +13:00
Ralph Slooten
a5ee550ba3 Rebuild changelog 2026-02-01 16:15:27 +13:00
Ralph Slooten
3e41beb214 Merge tag 'v1.29.0' into develop
Release v1.29.0
2026-02-01 16:12:05 +13:00
Ralph Slooten
43b8ba3dc6 Merge branch 'release/v1.29.0' 2026-02-01 16:12:00 +13:00
Ralph Slooten
d41eca3df7 Release v1.29.0 2026-02-01 16:11:59 +13:00
Ralph Slooten
e6fd638067 Detect if copy to clipboard is supported 2026-02-01 16:09:49 +13:00
Ralph Slooten
e2b1b2d0fe Code cleanup 2026-02-01 15:58:31 +13:00
Ralph Slooten
9b4ec97483 Minor UI tweaks 2026-02-01 15:44:13 +13:00
Ralph Slooten
e735904167 Chore: Update node dependencies 2026-02-01 15:40:59 +13:00
Ralph Slooten
94113222cc Chore: Update Go dependencies 2026-02-01 15:37:40 +13:00
Ralph Slooten
5414695508 Test: Add message summary attachment checksum tests 2026-02-01 15:34:06 +13:00
Ralph Slooten
dd74d46880 Feature: Option to display/hide attachment information in message view in web UI including checksums, content type & disposition
Resolves #625
2026-02-01 15:34:06 +13:00
Ralph Slooten
0bfbb4cc5f Feature: Include message attachment checksums (MD5, SHA1 & SHA254) in API message summary 2026-02-01 15:34:05 +13:00
Ralph Slooten
38c0c4fd47 Update webhook delay flag description 2026-02-01 15:34:05 +13:00
Roman Urbanovich
9391b075d0 Chore: Add support for webhook delay (#627) 2026-02-01 15:33:54 +13:00
Ralph Slooten
a87b2a9455 Update API CORS flag description 2026-02-01 15:33:53 +13:00
Ralph Slooten
8d18618e4a Test: Add CORS tests 2026-02-01 15:33:53 +13:00
Ralph Slooten
a63bcd9bd3 Chore: Add support for multi-origin CORS settings and apply to events websocket (#630) 2026-02-01 15:33:53 +13:00
Ralph Slooten
f33f9bec2d Merge branch 'release/v1.28.4' 2026-01-25 10:07:35 +13:00
Ralph Slooten
ff47ba96b8 Release v1.28.4 2026-01-25 10:07:35 +13:00
Ralph Slooten
b9f36312d7 Fix: Avoid error on image type assertion in thumbnail generation
Use imaging.Clone to ensure the image is always *image.NRGBA, preventing panics when decoding non-NRGBA images (e.g., JPEGs as *image.YCbCr).
2026-01-25 10:05:39 +13:00
Ralph Slooten
291c449591 Chore: Update node dependencies 2026-01-25 10:05:38 +13:00
Ralph Slooten
d7a4a60536 Chore: Update Go dependencies 2026-01-25 10:05:38 +13:00
Ralph Slooten
464ff68c34 Fix: Prevent nested MAIL command during an active SMTP transaction (#623) 2026-01-25 10:05:28 +13:00
Ralph Slooten
9383c5876b Fix: Ensure SMTP HELO/EHLO command is issued before MAIL FROM as per RFC 5321 (#621) 2026-01-23 17:27:13 +13:00
Ralph Slooten
a3616e52d9 Chore: Increase allowed SMTP email address length to 1024 chars & return clearer SMTP responses for failures (#620)
This goes against the RFC5321 recommendation, however enforcing the recommended limits is clearly causing issues with users, and it appears no investigated SMTP servers enforce the strict limits either.
2026-01-23 16:46:29 +13:00
Ralph Slooten
980e54c21f Merge tag 'v1.28.3' into develop
Release v1.28.3
2026-01-18 21:36:02 +13:00
Ralph Slooten
eac491cd89 Merge branch 'release/v1.28.3' 2026-01-18 21:35:55 +13:00
Ralph Slooten
12076bca72 Release v1.28.3 2026-01-18 21:35:54 +13:00
Ralph Slooten
028ca1d715 Chore: Update node dependencies 2026-01-18 12:24:54 +13:00
Ralph Slooten
7d7ba88e9c Chore: Update Go dependencies 2026-01-18 12:22:46 +13:00
Ralph Slooten
973fc1f975 Merge branch 'feature/GHSA-6jxm-fv7w-rw5j' into develop 2026-01-18 12:00:09 +13:00
Ralph Slooten
1679a0aba5 Security: Prevent Server-Side Request Forgery (SSRF) via HTML Check API ([GHSA-6jxm-fv7w-rw5j](https://github.com/axllent/mailpit/security/advisories/GHSA-6jxm-fv7w-rw5j)) 2026-01-18 11:58:24 +13:00
Ralph Slooten
4a4c149eed Formatting 2026-01-18 11:57:23 +13:00
Ralph Slooten
c01335f0e3 Merge branch 'feature/GHSA-54wq-72mp-cq7c' into develop 2026-01-18 11:53:11 +13:00
Ralph Slooten
181cb0714a Test: Add maximum email length validation tests - RFC5321 (section 4.5.3.1) 2026-01-18 11:51:23 +13:00
Ralph Slooten
00d52d5931 Fix: Validate maximum lengths of email addresses - RFC5321 (section 4.5.3.1) 2026-01-18 11:51:23 +13:00
Ralph Slooten
050da038af Test: Add SMTP tests for address compliancy (RFC 5322) and header injection 2026-01-18 11:51:23 +13:00
Ralph Slooten
36cc06c125 Security: Ensure SMTP TO & FROM addresses are RFC 5322 compliant and prevent header injection ([GHSA-54wq-72mp-cq7c](https://github.com/axllent/mailpit/security/advisories/GHSA-54wq-72mp-cq7c)) 2026-01-18 11:50:33 +13:00
Ralph Slooten
2734efbc66 Test: Update tag tests with length limits and @ character 2026-01-17 11:22:19 +13:00
Ralph Slooten
7cda4a36f1 Chore: Allow @ character in message tags & set max length to 100 characters per tag 2026-01-17 11:12:45 +13:00
Ralph Slooten
45b3676e52 Fix: Auto-tagging using SMTP username using plain auth (#617) 2026-01-16 13:50:15 +13:00
BTC-Tim
d50347d667 Fix: Correctly detect macOS group in install.sh (#619) 2026-01-16 10:12:11 +13:00
Omar Kurt
c035139b54 Chore: Fix formatting and update reporting instructions in SECURITY.md (#614) 2026-01-11 10:24:58 +13:00
Ralph Slooten
3108d82e06 Fix: Correctly render default addresses in release modal after settings change (#594) 2026-01-10 22:19:18 +13:00
Ralph Slooten
648d5863da Merge tag 'v1.28.2' into develop
Release v1.28.2
2026-01-10 16:16:14 +13:00
Ralph Slooten
585ea1dc30 Merge branch 'release/v1.28.2' 2026-01-10 16:16:06 +13:00
Ralph Slooten
c66a06379a Release v1.28.2 2026-01-10 16:16:05 +13:00
Ralph Slooten
c5c9292863 More reliable handling for default release email editing 2026-01-10 15:56:19 +13:00
Ralph Slooten
6f1f4f34c9 Security: Prevent Cross-Site WebSocket Hijacking (CSWSH) allowing unauthenticated access to message data [CVE-2026-22689](https://github.com/axllent/mailpit/security/advisories/GHSA-524m-q5m7-79mm) 2026-01-10 15:42:14 +13:00
Ralph Slooten
877a9159ce Delay bootstrap-tags init until after render 2026-01-08 16:23:24 +13:00
Ralph Slooten
c4582889ad Update default release address wording 2026-01-08 16:20:00 +13:00
Ralph Slooten
cd1cf695b9 Merge branch 'feature/default-release-address' into develop 2026-01-08 16:04:23 +13:00
Ralph Slooten
392904fd23 Chore: Avoid empty URL query parameter when returning to inbox from message view 2026-01-08 16:03:35 +13:00
Ralph Slooten
f0160c0e29 Feature: Allow default mail addresses to be set when releasing message (#594) 2026-01-08 16:03:35 +13:00
Ralph Slooten
f9024d1f77 Chore: Remove webkit warnings about missing template / render functions 2026-01-08 16:03:34 +13:00
Ralph Slooten
061f159293 Merge tag 'v1.28.1' into develop
Release v1.28.1
2026-01-06 15:38:14 +13:00
Ralph Slooten
e69a0d75c9 Merge branch 'release/v1.28.1' 2026-01-06 15:38:11 +13:00
Ralph Slooten
0847167694 Release v1.28.1 2026-01-06 15:38:11 +13:00
Ralph Slooten
6dd3587ec6 Move security commits to top of list 2026-01-06 15:35:49 +13:00
Ralph Slooten
2d1e38d4fd Chore: Update node dependencies 2026-01-06 15:34:20 +13:00
Ralph Slooten
153174f928 Chore: Update Go dependencies 2026-01-06 15:34:20 +13:00
Ralph Slooten
3b9b470c09 Security: Restrict screenshot proxy to only support asset links contained in messages [CVE-2026-21859](https://github.com/axllent/mailpit/security/advisories/GHSA-8v65-47jx-7mfr)
This fix prevents unrestricted network probing via the screenshot proxy by limiting requests to images, fonts and CSS links found within a message, and returns a generic HTTP error to the client when unsupported content types are requested, not found, or otherwise disallowed.

See CWE-918 Server-Side Request Forgery (SSRF)
2026-01-06 15:33:50 +13:00
dependabot[bot]
dd99a4bcf0 Chore: Bump esbuild from 0.25.12 to 0.27.2 (#611)
Bumps [esbuild](https://github.com/evanw/esbuild) from 0.25.12 to 0.27.2.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.25.12...v0.27.2)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-version: 0.27.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-01 22:16:37 +13:00
dependabot[bot]
5bf2f2796b Chore: Bump actions/setup-node from 5 to 6 (#598)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 5 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-01 22:13:15 +13:00
dependabot[bot]
a469655f65 Chore: Bump actions/stale from 10.0.0 to 10.1.1 (#604)
Bumps [actions/stale](https://github.com/actions/stale) from 10.0.0 to 10.1.1.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v10.0.0...v10.1.1)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: 10.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-01 22:12:43 +13:00
dependabot[bot]
432fedeafa Chore: Bump actions/cache from 4 to 5 (#607)
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-01 22:12:15 +13:00
dependabot[bot]
37e4ff4139 Chore: Bump actions/checkout from 5 to 6 (#610)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-01 22:11:51 +13:00
Ralph Slooten
2808316dd2 Temporarily disable swagger validation due to persistent service issues 2025-12-22 17:12:35 +13:00
Ralph Slooten
43d759b0fc Update close-stale-issues workflow to include close-issue-reason 2025-12-22 16:45:44 +13:00
Ralph Slooten
264222d599 Test: Increase swagger test timeout 2025-12-20 17:07:36 +13:00
Ralph Slooten
5e4bdb78b8 Test: Add inline message tests 2025-12-20 16:45:57 +13:00
Ralph Slooten
fc9572156b Merge tag 'v1.28.0' into develop
Release v1.28.0
2025-11-26 17:44:28 +13:00
Ralph Slooten
d52a0d550f Merge branch 'release/v1.28.0' 2025-11-26 17:44:26 +13:00
Ralph Slooten
fcce621f18 Release v1.28.0 2025-11-26 17:44:26 +13:00
Ralph Slooten
f4cd19aac2 Merge branch 'feature/updates' into develop 2025-11-26 17:33:38 +13:00
Ralph Slooten
46ccf866b2 Chore: Update caniemail test database 2025-11-26 17:32:49 +13:00
Ralph Slooten
266611fda0 Chore: Update node dependencies 2025-11-26 17:32:18 +13:00
Ralph Slooten
fe3920e3c6 Chore: Update Go dependencies 2025-11-26 17:29:03 +13:00
Ralph Slooten
ac02802d62 Merge branch 'feature/relay-smtp-errors' into develop 2025-11-26 16:34:39 +13:00
Ralph Slooten
7d6aab4e01 Refactor imports and improve logging in SMTP relay functionality 2025-11-26 16:30:28 +13:00
Ralph Slooten
36d8525557 Refactor command handlers to ignore unused parameters 2025-11-26 16:30:14 +13:00
Dennis
0f0a5d942f Feature: Optionally propagate SMTP errors (#588)
* forward smtp errors

* lint and formatting

* forward smtp errors in forward-impl
2025-11-26 16:17:44 +13:00
dependabot[bot]
b987006897 Bump golang.org/x/crypto from 0.43.0 to 0.45.0 (#586)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.43.0 to 0.45.0.
- [Commits](https://github.com/golang/crypto/compare/v0.43.0...v0.45.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.45.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-20 16:14:38 +13:00
dependabot[bot]
c8e0bee8bb Bump js-yaml from 4.1.0 to 4.1.1 (#585)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.0 to 4.1.1.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.0...4.1.1)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.1.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-17 08:08:55 +13:00
Ralph Slooten
3b0ae24c2a Merge tag 'v1.27.11' into develop
Release v1.27.11
2025-11-09 11:38:25 +13:00
Ralph Slooten
aca491f10c Merge branch 'release/v1.27.11' 2025-11-09 11:38:22 +13:00
Ralph Slooten
6724f0ccdd Release v1.27.11 2025-11-09 11:38:21 +13:00
Ralph Slooten
93088f3361 Chore: Add type assertion for value in imaging assignment 2025-11-09 11:33:51 +13:00
Ralph Slooten
e817bf5f7d Chore: Update node dependencies 2025-11-09 11:19:03 +13:00
Ralph Slooten
4d100a9ec3 Chore: Update Go dependencies 2025-11-09 11:16:20 +13:00
Ralph Slooten
958fa6cf1a Add thanks.dev link 2025-11-05 22:04:33 +13:00
Ralph Slooten
27e12474f5 Add link to Mailtrap 2025-11-04 16:57:45 +13:00
Ralph Slooten
302b269fb6 Merge tag 'v1.27.10' into develop
Release v1.27.10
2025-10-09 15:40:09 +13:00
Ralph Slooten
2d9157ffd3 Merge branch 'release/v1.27.10' 2025-10-09 15:40:06 +13:00
Ralph Slooten
242c96244a Release v1.27.10 2025-10-09 15:40:06 +13:00
Ralph Slooten
d308e7f30b Merge branch 'feature/fix' into develop 2025-10-09 15:37:09 +13:00
Ralph Slooten
85a9cc3c2b Chore: Update node dependencies 2025-10-09 15:36:16 +13:00
Ralph Slooten
f94ce556e5 Chore: Update Go dependencies 2025-10-09 15:33:04 +13:00
Ralph Slooten
5ad8619893 Fix: Prevent potential information disclosure via indirect expvar library (Prometheus)
This is a security fix which prevents potential information disclosure due to a pre-registered HTTP route. The Prometheus client imports the go stdlib expvar, which in turn is auto-registers `/debug/vars` on the default servemux. This fix ensures no default/global routes are inherited via the http library.
2025-10-08 17:32:05 +13:00
Ralph Slooten
8d692b6bd9 Chore: Update GitHub Actions 2025-10-08 17:32:05 +13:00
Ralph Slooten
99ab38fbba Chore: Add tooltip to messages nav dropdown 2025-10-08 17:32:05 +13:00
Ralph Slooten
2cf040e787 Chore: Update GitHub Actions 2025-10-01 21:53:32 +13:00
Ralph Slooten
cde80bf0fd Chore: Add tooltip to messages nav dropdown 2025-09-29 17:07:40 +13:00
Ralph Slooten
1a41d433c6 Merge tag 'v1.27.9' into develop
Release v1.27.9
2025-09-29 15:41:06 +13:00
Ralph Slooten
49557e8e59 Merge branch 'release/v1.27.9' 2025-09-29 15:41:03 +13:00
Ralph Slooten
339f6ef31d Release v1.27.9 2025-09-29 15:41:03 +13:00
Ralph Slooten
2e187cfcef Chore: Update node dependencies 2025-09-29 15:14:29 +13:00
Ralph Slooten
39ecefa108 Chore: Update Go dependencies 2025-09-29 15:11:45 +13:00
Ralph Slooten
ae65312d02 Chore: Update navbar theme to use data-bs-theme attribute for consistency 2025-09-26 14:50:27 +12:00
Ralph Slooten
0770bd8d19 Chore: Add margin to icons in release and delete buttons for consistent spacing 2025-09-26 14:50:06 +12:00
Ralph Slooten
e2314fb3b9 Chore: UI tweaks to pagination layout for clearer navigation (#568) 2025-09-26 14:48:51 +12:00
Ralph Slooten
1dd0bf3d29 Merge tag 'v1.27.8' into develop
Release v1.27.8
2025-09-14 22:34:07 +12:00
Ralph Slooten
568ad5da62 Merge branch 'release/v1.27.8' 2025-09-14 22:34:04 +12:00
Ralph Slooten
d3063ea248 Release v1.27.8 2025-09-14 22:34:03 +12:00
Ralph Slooten
6ccc294a1e Chore: Update caniemail test database 2025-09-14 22:23:44 +12:00
Ralph Slooten
5629f39d40 Chore: Update node dependencies 2025-09-14 22:22:55 +12:00
Ralph Slooten
314f30bee5 Chore: Update Go dependencies 2025-09-14 22:22:09 +12:00
Ralph Slooten
5c8931c04d Merge tag 'v1.27.7' into develop
Release v1.27.7
2025-08-27 15:57:12 +12:00
Ralph Slooten
ca6357f262 Merge branch 'release/v1.27.7' 2025-08-27 15:57:09 +12:00
Ralph Slooten
3645219615 Release v1.27.7 2025-08-27 15:57:09 +12:00
Ralph Slooten
7d74516270 Fix: Move HELO/EHLO hostname setting to the correct position in SMTP client creation (#558) 2025-08-26 12:17:01 +12:00
Ralph Slooten
fb1a06bc86 Merge tag 'v1.27.6' into develop
Release v1.27.6
2025-08-24 13:47:29 +12:00
Ralph Slooten
7809a26374 Merge branch 'release/v1.27.6' 2025-08-24 13:47:25 +12:00
Ralph Slooten
120f078a32 Release v1.27.6 2025-08-24 13:47:25 +12:00
Ralph Slooten
776912d38a Chore: Update node dependencies 2025-08-24 13:44:27 +12:00
Ralph Slooten
e3b37943a8 Chore: Update Go dependencies 2025-08-24 13:41:21 +12:00
Stéphan Kochen
5054d98701 Feature: Add optional --no-release-check to version subcommand (#557) 2025-08-22 22:44:00 +12:00
Peter Krawczyk
8ce6fc0db5 Chore: Set HELO/EHLO hostname when connecting to external SMTP server (#556)
When a message is forwarded or released, Mailpit introduces itself as
`localhost` to the upstream server. This happens because `net/smtp` forces the
value to be `localhost` if `client.Hello` is not called. This is explicitly
documented at https://pkg.go.dev/net/smtp#Client.Hello

Therefore, both `internal/smtpd/relay.go` (`createRelaySMTPClient`) and
`internal/smtpd/forward.go` (`createForwardingSMTPClient`) should either call
`client.Hello(os.Hostname())` or create a config (perhaps `config.HeloHostname`)
and use `client.Hello()` with that value immediately before returning from
either of those functions. (The HELO/EHLO command comes after TLS negotiation
but before any other SMTP commands.) This commit does the former.

Without this feature, Mailpit cannot be used in combination with Google
Workspace's SMTP Relay functionality, as it rejects any connection that
identifies itself as `localhost`.

Relates to #146
2025-08-22 16:04:03 +12:00
Ralph Slooten
933d064a51 Merge tag 'v1.27.5' into develop
Release v1.27.5
2025-08-17 12:41:46 +12:00
Ralph Slooten
ad26ca34e5 Merge branch 'release/v1.27.5' 2025-08-17 12:41:43 +12:00
Ralph Slooten
531801f934 Release v1.27.5 2025-08-17 12:41:42 +12:00
Ralph Slooten
0faa71310e Chore: Update caniemail test database 2025-08-17 12:35:45 +12:00
Ralph Slooten
646e93c58b Chore: Update node dependencies 2025-08-17 12:34:59 +12:00
Ralph Slooten
854844924f Chore: Update Go dependencies 2025-08-17 12:31:49 +12:00
Felipe
343db8bb61 Fix: Support optional UIDL argument in POP3 server (#552)
* fix: use single-line response when UIDL has an argument

The test changes included here don't necessarily deal with the fact that
the response used to be multi-line: the failure wouldn't occur during
the `c.Uidl()` calls, but rather on the next one as the client would
still have data from the server to receive, causing a parsing error like
so:

    pop3_test.go:103: strconv.Atoi: parsing "unique-id": invalid syntax

The server now correctly replies with a single line response when an
argument is passed, as required by [the spec][1]

[1]: https://www.rfc-editor.org/rfc/rfc1939.html#page-12

* fix: UIDL accepts at most one argument
2025-08-17 12:24:53 +12:00
Ralph Slooten
781d8d2332 Merge tag 'v1.27.4' into develop
Release v1.27.4
2025-08-10 21:26:12 +12:00
Ralph Slooten
618d1f77b5 Merge branch 'release/v1.27.4' 2025-08-10 21:25:52 +12:00
Ralph Slooten
5577b748af Release v1.27.4 2025-08-10 21:25:51 +12:00
Ralph Slooten
4619d9be88 Chore: Update caniemail test database 2025-08-10 21:18:23 +12:00
Ralph Slooten
6051952a9b Chore: Update node dependencies 2025-08-10 21:17:32 +12:00
Ralph Slooten
a54697b3de Chore: Update Go dependencies 2025-08-10 21:14:38 +12:00
Ralph Slooten
f6bb0d1ffd Merge branch 'feature/drop-rejected-recipients' into develop 2025-08-10 21:09:29 +12:00
Ralph Slooten
41ef4ecd60 Rename smtp-silently-drop-rejected-recipients to smtp-ignore-rejected-recipients 2025-08-10 21:04:22 +12:00
Matthias Gliwka
39d80df809 Feature: Allow rejected SMTP recipients to be silently dropped (#549) 2025-08-10 20:34:26 +12:00
Ralph Slooten
be95839838 Merge tag 'v1.27.3' into develop
Release v1.27.3
2025-07-29 01:22:02 +12:00
Ralph Slooten
8f187fe275 Merge branch 'release/v1.27.3' 2025-07-29 01:21:55 +12:00
Ralph Slooten
bb2793354a Release v1.27.3 2025-07-29 01:21:53 +12:00
Ralph Slooten
42aa38ddeb Fix: Fix sendmail when using an --smtp-addr <ip>:<port> (#542) 2025-07-29 01:20:55 +12:00
Ralph Slooten
7423b9660b Merge tag 'v1.27.2' into develop
Release v1.27.2
2025-07-27 12:36:34 +12:00
Ralph Slooten
0b7503261c Merge branch 'release/v1.27.2' 2025-07-27 12:36:30 +12:00
Ralph Slooten
e43be79968 Release v1.27.2 2025-07-27 12:36:29 +12:00
Ralph Slooten
70855a50c5 Chore: Update node dependencies 2025-07-27 12:29:56 +12:00
Ralph Slooten
0b21a3aba2 Chore: Update Go dependencies 2025-07-27 12:28:09 +12:00
Ralph Slooten
507217844b Security: Add ReadHeaderTimeout to Prometheus metrics server 2025-07-25 20:39:13 +12:00
Ralph Slooten
5a4d13b15a Security: Prevent integer overflow conversion to uint64 2025-07-25 20:33:27 +12:00
Ralph Slooten
fbc1dc6118 Do not expose unnecessary Prometheus functions 2025-07-25 20:33:27 +12:00
Ralph Slooten
2a7aa33a0a Fix: Do not check latest release for Prometheus statistics (#522) 2025-07-25 20:33:20 +12:00
dependabot[bot]
45f07d3c9b Bump form-data from 4.0.3 to 4.0.4
---
updated-dependencies:
- dependency-name: form-data
  dependency-version: 4.0.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-24 17:32:03 +12:00
dependabot[bot]
894220dc44 Bump axios from 1.10.0 to 1.11.0
Bumps [axios](https://github.com/axios/axios) from 1.10.0 to 1.11.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.10.0...v1.11.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.11.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-24 17:30:56 +12:00
Ralph Slooten
cce21854b9 Chore: Refactor JS functions and remove unused parameters 2025-07-24 17:27:11 +12:00
Ralph Slooten
33fe814c34 Chore: Update eslint config, remove neostandard 2025-07-24 17:26:20 +12:00
Ralph Slooten
df75064009 Merge branch 'feature/snakeoil' into develop 2025-07-24 17:04:25 +12:00
Ralph Slooten
e1ed21abff Chore: Allow sendmail to send to untrusted TLS server 2025-07-24 17:04:15 +12:00
Ralph Slooten
f3e3536cdb Feature: Add ability to generate self-signed (snakeoil) certificates for UI, SMTP and POP3 (#539) 2025-07-24 17:02:50 +12:00
Ralph Slooten
38c343867e Merge branch 'feature/535-bug' into develop 2025-07-18 23:43:17 +12:00
Ralph Slooten
75504c7bba Fix: Support angle brackets for text/plain URLs with spaces (#535) 2025-07-18 23:43:05 +12:00
Dennis
79323df3bd Fix: Use MaxMessages to determine pruning (#536) 2025-07-16 22:16:25 +12:00
Ralph Slooten
5a672df0fc Merge tag 'v1.27.1' into develop
Release v1.27.1
2025-07-06 17:34:56 +12:00
Ralph Slooten
72730ba470 Merge branch 'release/v1.27.1' 2025-07-06 17:34:50 +12:00
Ralph Slooten
76d9a410b8 Release v1.27.1 2025-07-06 17:34:49 +12:00
Ralph Slooten
7ca84d3b0d Chore: Update node dependencies 2025-07-06 17:29:51 +12:00
Ralph Slooten
d430e38aad Chore: Update Go dependencies 2025-07-06 17:22:35 +12:00
Ralph Slooten
2d1fb7cf14 Chore: Allow unknown href link protocols in HTML view such as myapp:// (#532) 2025-07-01 08:01:09 +12:00
Ralph Slooten
8634c9e8f2 Rebuild CHANGELOG (glitch in the matrix) 2025-06-29 00:04:56 +12:00
Ralph Slooten
e74237e71c Merge tag 'v1.27.0' into develop
Release v1.27.0
2025-06-28 23:54:32 +12:00
92 changed files with 4057 additions and 4829 deletions

1
.github/FUNDING.yml vendored
View File

@@ -1,3 +1,4 @@
# These are supported funding model platforms
github: [axllent]
thanks_dev: u/gh/axllent

10
.github/SECURITY.md vendored
View File

@@ -2,10 +2,12 @@
Your efforts to responsibly disclose your findings are appreciated.
** **Please do _not_ report security vulnerabilities through public GitHub issues.** **
**Please do not report security vulnerabilities through public GitHub issues.**
If you believe you have found a **security vulnerability**, then please report it to security@axllent.org so
your findings can be investigated, and if confirmed, fixed and released in a timely manner.
If you believe you have found a security vulnerability, you can report it using one of the following methods:
1. **GitHub Security Advisory (Recommended):** Use the "Report a vulnerability" button in the [Security tab](../../security/advisories/new) of this repository.
2. **Email:** Send your findings to security@axllent.org
Your report should include:
@@ -14,6 +16,6 @@ Your report should include:
- Reproduction steps (if applicable)
- Any other details you think are likely to be important
You should receive an initial acknowledgement within 24 hours in most cases, and will kept updated throughout the process.
You should receive an initial acknowledgement within 24 hours in most cases, and will be kept updated throughout the process.
With your consent, your contributions will be publicly acknowledged.

1
.github/cliff.toml vendored
View File

@@ -28,6 +28,7 @@ trim = true
# HTML comments added for grouping order, stripped on generation
commit_parsers = [
{body = ".*security", group = "<!-- 1 -->Security"},
{message = "(?i)^security", group = "<!-- 1 -->Security"},
{message = "(?i)^feat", group = "<!-- 2 -->Feature"},
{message = "(?i)^chore", group = "<!-- 3 -->Chore"},
{message = "(?i)^libs", group = "<!-- 3 -->Chore"},

View File

@@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Set up QEMU
uses: docker/setup-qemu-action@v3

View File

@@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Set up QEMU
uses: docker/setup-qemu-action@v3

View File

@@ -10,12 +10,13 @@ jobs:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9.1.0
- uses: actions/stale@v10.1.1
with:
days-before-issue-stale: 7
days-before-issue-close: 3
exempt-issue-labels: "enhancement,bug,awaiting feedback"
stale-issue-label: "stale"
close-issue-reason: "completed"
stale-issue-message: "This issue has been marked as stale because it has been open for 7 days with no activity."
close-issue-message: "This issue was closed because there has been no activity since being marked as stale."
days-before-pr-stale: -1

View File

@@ -38,7 +38,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL

View File

@@ -21,10 +21,10 @@ jobs:
- goarch: arm
goos: windows
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
# build the assets
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: 22
cache: 'npm'

View File

@@ -17,9 +17,9 @@ jobs:
# the HTTP address the rqlite node should advertise
HTTP_ADV_ADDR: "localhost:4001"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: 'stable'
cache-dependency-path: "**/*.sum"

View File

@@ -12,13 +12,13 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go-version }}
cache: false
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Go environment
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: |
~/.cache/go-build
@@ -38,7 +38,7 @@ jobs:
# build the assets
- name: Set up node environment
if: startsWith(matrix.os, 'ubuntu') == true
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 22
cache: 'npm'
@@ -52,9 +52,10 @@ jobs:
if: startsWith(matrix.os, 'ubuntu') == true
run: npm run package
# validate the swagger file
- name: Validate OpenAPI definition
if: startsWith(matrix.os, 'ubuntu') == true
uses: swaggerexpert/swagger-editor-validate@v1
with:
definition-file: server/ui/api/v1/swagger.json
# # validate the swagger file
# - name: Validate OpenAPI definition
# if: startsWith(matrix.os, 'ubuntu') == true
# uses: swaggerexpert/swagger-editor-validate@v1
# with:
# definition-file: server/ui/api/v1/swagger.json
# default-timeout: 20000

View File

@@ -2,16 +2,249 @@
Notable changes to Mailpit will be documented in this file.
## [v1.27.0]
## [v1.29.2]
### Feature
- Store username with messages, auto-tag, and UI display ([#521](https://github.com/axllent/mailpit/issues/521))
- Allow version checking to be disabled ([#524](https://github.com/axllent/mailpit/issues/524))
### Security
- Prevent Server-Side Request Forgery (SSRF) via Link Check API ([GHSA-mpf7-p9x7-96r3](https://github.com/axllent/mailpit/security/advisories/GHSA-mpf7-p9x7-96r3))
### Chore
- Apply linting to all JavaScript/Vue files with eslint & prettier
- Upgrade eslint JavaScript linting
- Update Go dependencies
- Update node dependencies
- Update caniemail test database
### Fix
- Update install instructions when setting INSTALL_PATH
- Include 8BITMIME in SMTPD EHLO response ([#648](https://github.com/axllent/mailpit/issues/648))
## [v1.29.1]
### Chore
- Add CORS error logging and update error messages for failed CORS requests
- Bump axios from 1.13.4 to 1.13.5
- Update Go dependencies
- Update node dependencies
### Fix
- Enable "Mark all read" button (Inbox) when new message is received
## [v1.29.0]
### Feature
- Include message attachment checksums (MD5, SHA1 & SHA254) in API message summary
- Option to display/hide attachment information in message view in web UI including checksums, content type & disposition
### Chore
- Add support for multi-origin CORS settings and apply to events websocket ([#630](https://github.com/axllent/mailpit/issues/630))
- Add support for webhook delay ([#627](https://github.com/axllent/mailpit/issues/627))
- Update Go dependencies
- Update node dependencies
### Test
- Add CORS tests
- Add message summary attachment checksum tests
## [v1.28.4]
### Chore
- Increase allowed SMTP email address length to 1024 chars & return clearer SMTP responses for failures ([#620](https://github.com/axllent/mailpit/issues/620))
- Update Go dependencies
- Update node dependencies
### Fix
- Ensure SMTP HELO/EHLO command is issued before MAIL FROM as per RFC 5321 ([#621](https://github.com/axllent/mailpit/issues/621))
- Prevent nested MAIL command during an active SMTP transaction ([#623](https://github.com/axllent/mailpit/issues/623))
- Avoid error on image type assertion in thumbnail generation
## [v1.28.3]
### Security
- Ensure SMTP TO & FROM addresses are RFC 5322 compliant and prevent header injection ([GHSA-54wq-72mp-cq7c](https://github.com/axllent/mailpit/security/advisories/GHSA-54wq-72mp-cq7c))
- Prevent Server-Side Request Forgery (SSRF) via HTML Check API ([GHSA-6jxm-fv7w-rw5j](https://github.com/axllent/mailpit/security/advisories/GHSA-6jxm-fv7w-rw5j))
### Chore
- Fix formatting and update reporting instructions in SECURITY.md ([#614](https://github.com/axllent/mailpit/issues/614))
- Allow `@` character in message tags & set max length to 100 characters per tag
- Update Go dependencies
- Update node dependencies
### Fix
- Correctly render default addresses in release modal after settings change ([#594](https://github.com/axllent/mailpit/issues/594))
- Correctly detect macOS group in install.sh ([#619](https://github.com/axllent/mailpit/issues/619))
- Auto-tagging using SMTP username using plain auth ([#617](https://github.com/axllent/mailpit/issues/617))
- Validate maximum lengths of email addresses - RFC5321 (section 4.5.3.1)
### Test
- Update tag tests with length limits and `@` character
- Add SMTP tests for address compliancy (RFC 5322) and header injection
- Add maximum email length validation tests - RFC5321 (section 4.5.3.1)
## [v1.28.2]
### Security
- Prevent Cross-Site WebSocket Hijacking (CSWSH) allowing unauthenticated access to message data [CVE-2026-22689](https://github.com/axllent/mailpit/security/advisories/GHSA-524m-q5m7-79mm)
### Feature
- Allow default mail addresses to be set when releasing message ([#594](https://github.com/axllent/mailpit/issues/594))
### Chore
- Remove webkit warnings about missing template / render functions
- Avoid empty URL query parameter when returning to inbox from message view
## [v1.28.1]
### Security
- Restrict screenshot proxy to only support asset links contained in messages [CVE-2026-21859](https://github.com/axllent/mailpit/security/advisories/GHSA-8v65-47jx-7mfr)
### Chore
- Bump actions/checkout from 5 to 6 ([#610](https://github.com/axllent/mailpit/issues/610))
- Bump actions/cache from 4 to 5 ([#607](https://github.com/axllent/mailpit/issues/607))
- Bump actions/stale from 10.0.0 to 10.1.1 ([#604](https://github.com/axllent/mailpit/issues/604))
- Bump actions/setup-node from 5 to 6 ([#598](https://github.com/axllent/mailpit/issues/598))
- Bump esbuild from 0.25.12 to 0.27.2 ([#611](https://github.com/axllent/mailpit/issues/611))
- Update Go dependencies
- Update node dependencies
### Test
- Add inline message tests
- Increase swagger test timeout
## [v1.28.0]
### Feature
- Optionally propagate SMTP errors ([#588](https://github.com/axllent/mailpit/issues/588))
### Chore
- Update Go dependencies
- Update node dependencies
- Update caniemail test database
## [v1.27.11]
### Chore
- Update Go dependencies
- Update node dependencies
- Add type assertion for value in imaging assignment
## [v1.27.10]
### Security
- Prevent potential information disclosure via indirect expvar library (Prometheus)
### Chore
- Add tooltip to messages nav dropdown
- Update GitHub Actions
- Add tooltip to messages nav dropdown
- Update GitHub Actions
- Update Go dependencies
- Update node dependencies
## [v1.27.9]
### Chore
- UI tweaks to pagination layout for clearer navigation ([#568](https://github.com/axllent/mailpit/issues/568))
- Add margin to icons in release and delete buttons for consistent spacing
- Update navbar theme to use data-bs-theme attribute for consistency
- Update Go dependencies
- Update node dependencies
## [v1.27.8]
### Chore
- Update Go dependencies
- Update node dependencies
- Update caniemail test database
## [v1.27.7]
### Fix
- Move HELO/EHLO hostname setting to the correct position in SMTP client creation ([#558](https://github.com/axllent/mailpit/issues/558))
## [v1.27.6]
### Feature
- Add optional --no-release-check to version subcommand ([#557](https://github.com/axllent/mailpit/issues/557))
### Chore
- Set HELO/EHLO hostname when connecting to external SMTP server ([#556](https://github.com/axllent/mailpit/issues/556))
- Update Go dependencies
- Update node dependencies
## [v1.27.5]
### Chore
- Update Go dependencies
- Update node dependencies
- Update caniemail test database
### Fix
- Support optional UIDL argument in POP3 server ([#552](https://github.com/axllent/mailpit/issues/552))
## [v1.27.4]
### Feature
- Allow rejected SMTP recipients to be silently dropped ([#549](https://github.com/axllent/mailpit/issues/549))
### Chore
- Update Go dependencies
- Update node dependencies
- Update caniemail test database
## [v1.27.3]
### Fix
- Fix sendmail when using an `--smtp-addr <ip>:<port>` ([#542](https://github.com/axllent/mailpit/issues/542))
## [v1.27.2]
### Security
- Prevent integer overflow conversion to uint64
- Add ReadHeaderTimeout to Prometheus metrics server
### Feature
- Add ability to generate self-signed (snakeoil) certificates for UI, SMTP and POP3 ([#539](https://github.com/axllent/mailpit/issues/539))
### Chore
- Allow sendmail to send to untrusted TLS server
- Update eslint config, remove neostandard
- Refactor JS functions and remove unused parameters
- Update Go dependencies
- Update node dependencies
### Fix
- Use MaxMessages to determine pruning ([#536](https://github.com/axllent/mailpit/issues/536))
- Support angle brackets for text/plain URLs with spaces ([#535](https://github.com/axllent/mailpit/issues/535))
- Do not check latest release for Prometheus statistics ([#522](https://github.com/axllent/mailpit/issues/522))
## [v1.27.1]
### Chore
- Allow unknown href link protocols in HTML view such as myapp:// ([#532](https://github.com/axllent/mailpit/issues/532))
- Update Go dependencies
- Update node dependencies
## [v1.27.0]
### Chore
- Remove unused functionality/deadcode (golangci-lint)
- Refactor error handling and resource management across multiple files (golangci-lint)
- Refactor API Swagger definitions and remove unused structs
@@ -21,9 +254,23 @@ Notable changes to Mailpit will be documented in this file.
- Update node dependencies
### Fix
- Improve version polling, add thread safety and exponential backoff ([#523](https://github.com/axllent/mailpit/issues/523))
- Align websocket new message values with global Message Summary (no null values) ([#526](https://github.com/axllent/mailpit/issues/526))
## [v1.26.2]
### Feature
- Store username with messages, auto-tag, and UI display ([#521](https://github.com/axllent/mailpit/issues/521))
- Allow version checking to be disabled ([#524](https://github.com/axllent/mailpit/issues/524))
### Chore
- Apply linting to all JavaScript/Vue files with eslint & prettier
- Update Go dependencies
- Update node dependencies
### Fix
- Improve version polling, add thread safety and exponential backoff ([#523](https://github.com/axllent/mailpit/issues/523))
### Test
- Add JavaScript linting tests to CI
- Add Go linting (gofmt) to CI
@@ -1615,6 +1862,9 @@ Notable changes to Mailpit will be documented in this file.
## [1.1.4]
### Security
- Add restrictive HTTP Content-Security-Policy
### Feature
- Add --quiet flag to display only errors
@@ -1623,9 +1873,6 @@ Notable changes to Mailpit will be documented in this file.
- Add favicon unread message counter
- Minor UI color change & unread count position adjustment
### Security
- Add restrictive HTTP Content-Security-Policy
## [1.1.3]
@@ -1712,14 +1959,14 @@ Notable changes to Mailpit will be documented in this file.
## [0.1.2]
### Feature
- Optional browser notifications (HTTPS only)
### Security
- Use strconv.Atoi() for safe string to int conversions
- Sanitize mailbox names
- Don't allow tar files containing a ".."
### Feature
- Optional browser notifications (HTTPS only)
## [0.1.1]

View File

@@ -1,16 +1,10 @@
# Contributing guide
Thank you for your interest in contributing to Mailpit, your help is greatly appreciated! Please follow the guidelines below to ensure a smooth contribution process.
## Code of conduct
Please be respectful and considerate in all interactions. Mailpit is open source and free of charge, however is the result of thousands of hours of work.
# Contributing to Mailpit
Thank you for your interest in contributing to Mailpit!
## Reporting issues and feature requests
If you find a bug or have a feature request, please [open an issue](https://github.com/axllent/mailpit/issues) and provide as much detail as possible. Pleas do not report security issues here (see below).
If you find a bug or have a feature request, please [open an issue](https://github.com/axllent/mailpit/issues) and provide as much detail as possible. Please **do not** report security issues here (see below).
## Reporting security issues
@@ -18,44 +12,11 @@ If you find a bug or have a feature request, please [open an issue](https://gith
Please do not report security issues publicly in GitHub. Refer to [SECURITY document](https://github.com/axllent/mailpit/blob/develop/.github/SECURITY.md) for instructions and contact information.
## Contributing code
## How to contribute (pull request)
Please ensure your code is clean and well-commented, and [passes linting](https://mailpit.axllent.org/docs/development/code-linting/) before submitting a Pull Request. Contributions should enhance the functionality or usability of Mailpit, focusing on quality over quantity.
1. **Fork the repository**
Click the "Fork" button at the top right of this repository to create your own copy.
Note that while assistance from AI tools is perfectly acceptable, **"[vibe coded](https://en.wikipedia.org/wiki/Vibe_coding)" pull requests will most likely not be accepted.**
We value the unique insights and creativity that individual contributors bring to the project.
2. **Clone your fork**
```bash
git clone https://github.com/your-username/mailpit.git
cd mailpit
```
3. **Create a branch**
Use a descriptive branch name:
```bash
git checkout -b feature/your-feature-name
```
4. **Make your changes**
Write clear, concise code and include comments where necessary.
5. **Test your changes**
Run all tests to ensure nothing is broken. This is a mandatory step as pull requests cannot be merged unless they pass the automated testing.
6. **Ensure your changes pass linting**
Ensure your changes pass the [code linting](https://mailpit.axllent.org/docs/development/code-linting/) requirements. This is a mandatory step as pull requests cannot be merged unless they pass the automated linting tests.
7. **Commit and push**
Write a clear commit message:
```bash
git add .
git commit -m "Describe your changes"
git push origin feature/your-feature-name
```
8. **Open a pull request**
Go to your fork on GitHub and open a pull request against the `develop` branch. Fill out the PR template and describe your changes.
---
Thank you for helping make this project awesome!
Thank you for your understanding and for contributing to Mailpit!

View File

@@ -79,7 +79,7 @@ sudo sh < <(curl -sL https://raw.githubusercontent.com/axllent/mailpit/develop/i
You can also change the install path to something else by setting the `INSTALL_PATH` environment, for example:
```shell
INSTALL_PATH=/usr/bin sudo sh < <(curl -sL https://raw.githubusercontent.com/axllent/mailpit/develop/install.sh)
sudo INSTALL_PATH=/usr/bin sh < <(curl -sL https://raw.githubusercontent.com/axllent/mailpit/develop/install.sh)
```
@@ -115,3 +115,10 @@ Please refer to [the documentation](https://mailpit.axllent.org/docs/install/tes
Mailpit's SMTP server (default on port 1025), so you will likely need to configure your sending application to deliver mail via that port.
A common MTA (Mail Transfer Agent) that delivers system emails to an SMTP server is `sendmail`, used by many applications, including PHP.
Mailpit can also act as substitute for sendmail. For instructions on how to set this up, please refer to the [sendmail documentation](https://mailpit.axllent.org/docs/install/sendmail/).
---
<p align="center">
For team features, multiple inboxes, and a hosted setup, try
<a href="https://mailtrap.io/?ref=mailpit">Mailtrap</a>, our friendly companion.
</p>

View File

@@ -17,7 +17,7 @@ The database can either be the database file (eg: --database /var/lib/mailpit/ma
URL of a running Mailpit instance (eg: --http http://127.0.0.1/). If dumping over HTTP, the URL
should be the base URL of your running Mailpit instance, not the link to the API itself.`,
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
Run: func(_ *cobra.Command, args []string) {
if err := dump.Sync(args[0]); err != nil {
logger.Log().Fatal(err)
}

View File

@@ -30,7 +30,7 @@ Mailpit server. Each email must be a separate file (eg: Maildir format, not mbox
The --recent flag will only consider files with a modification date within the last X days.`,
// Hidden: true,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
Run: func(_ *cobra.Command, args []string) {
var count int
var total int
var per100start = time.Now()

View File

@@ -28,7 +28,7 @@ status 1 if unhealthy.
If running within Docker, it should automatically detect environment
settings to determine the HTTP bind interface & port.
`,
Run: func(cmd *cobra.Command, args []string) {
Run: func(_ *cobra.Command, _ []string) {
webroot := strings.TrimRight(path.Join("/", config.Webroot, "/"), "/") + "/"
proto := "http"
if useHTTPS {

View File

@@ -18,7 +18,7 @@ var reindexCmd = &cobra.Command{
If you have several thousand messages in your mailbox, then it is advised to shut down
Mailpit while you reindex as this process will likely result in database locking issues.`,
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
Run: func(_ *cobra.Command, args []string) {
config.Database = args[0]
config.MaxMessages = 0

View File

@@ -103,8 +103,9 @@ func init() {
rootCmd.Flags().StringVar(&config.UIAuthFile, "ui-auth-file", config.UIAuthFile, "A password file for web UI & API authentication")
rootCmd.Flags().StringVar(&config.UITLSCert, "ui-tls-cert", config.UITLSCert, "TLS certificate for web UI (HTTPS) - requires ui-tls-key")
rootCmd.Flags().StringVar(&config.UITLSKey, "ui-tls-key", config.UITLSKey, "TLS key for web UI (HTTPS) - requires ui-tls-cert")
rootCmd.Flags().StringVar(&server.AccessControlAllowOrigin, "api-cors", server.AccessControlAllowOrigin, "Set API CORS Access-Control-Allow-Origin header")
rootCmd.Flags().StringVar(&server.AccessControlAllowOrigin, "api-cors", server.AccessControlAllowOrigin, "Set CORS origin(s) for the API, comma-separated (eg: example.com,foo.com)")
rootCmd.Flags().BoolVar(&config.BlockRemoteCSSAndFonts, "block-remote-css-and-fonts", config.BlockRemoteCSSAndFonts, "Block access to remote CSS & fonts")
rootCmd.Flags().BoolVar(&config.AllowInternalHTTPRequests, "allow-internal-http-requests", config.AllowInternalHTTPRequests, "Allow link-checker & screenshots to access internal IP addresses")
rootCmd.Flags().StringVar(&config.EnableSpamAssassin, "enable-spamassassin", config.EnableSpamAssassin, "Enable integration with SpamAssassin")
rootCmd.Flags().BoolVar(&config.AllowUntrustedTLS, "allow-untrusted-tls", config.AllowUntrustedTLS, "Do not verify HTTPS certificates (link checker & screenshots)")
rootCmd.Flags().BoolVar(&config.DisableHTTPCompression, "disable-http-compression", config.DisableHTTPCompression, "Disable HTTP compression support (web UI & API)")
@@ -126,6 +127,7 @@ func init() {
rootCmd.Flags().BoolVar(&config.SMTPStrictRFCHeaders, "smtp-strict-rfc-headers", config.SMTPStrictRFCHeaders, "Return SMTP error if message headers contain <CR><CR><LF>")
rootCmd.Flags().IntVar(&config.SMTPMaxRecipients, "smtp-max-recipients", config.SMTPMaxRecipients, "Maximum SMTP recipients allowed")
rootCmd.Flags().StringVar(&config.SMTPAllowedRecipients, "smtp-allowed-recipients", config.SMTPAllowedRecipients, "Only allow SMTP recipients matching a regular expression (default allow all)")
rootCmd.Flags().BoolVar(&config.SMTPIgnoreRejectedRecipients, "smtp-ignore-rejected-recipients", config.SMTPIgnoreRejectedRecipients, "Ignore rejected SMTP recipients with 2xx response")
rootCmd.Flags().BoolVar(&smtpd.DisableReverseDNS, "smtp-disable-rdns", smtpd.DisableReverseDNS, "Disable SMTP reverse DNS lookups")
// SMTP relay
@@ -159,6 +161,7 @@ func init() {
// Webhook
rootCmd.Flags().StringVar(&config.WebhookURL, "webhook-url", config.WebhookURL, "Send a webhook request for new messages")
rootCmd.Flags().IntVar(&webhook.RateLimit, "webhook-limit", webhook.RateLimit, "Limit webhook requests per second")
rootCmd.Flags().IntVar(&webhook.Delay, "webhook-delay", webhook.Delay, "Delay in seconds before sending webhook requests (default 0)")
// DEPRECATED FLAG 2024/04/12 - but will not be removed to maintain backwards compatibility
rootCmd.Flags().StringVar(&config.Database, "db-file", config.Database, "Database file to store persistent data")
@@ -248,6 +251,9 @@ func initConfigFromEnv() {
if getEnabledFromEnv("MP_BLOCK_REMOTE_CSS_AND_FONTS") {
config.BlockRemoteCSSAndFonts = true
}
if getEnabledFromEnv("MP_ALLOW_INTERNAL_HTTP_REQUESTS") {
config.AllowInternalHTTPRequests = true
}
if len(os.Getenv("MP_ENABLE_SPAMASSASSIN")) > 0 {
config.EnableSpamAssassin = os.Getenv("MP_ENABLE_SPAMASSASSIN")
}
@@ -301,6 +307,9 @@ func initConfigFromEnv() {
if len(os.Getenv("MP_SMTP_ALLOWED_RECIPIENTS")) > 0 {
config.SMTPAllowedRecipients = os.Getenv("MP_SMTP_ALLOWED_RECIPIENTS")
}
if getEnabledFromEnv("MP_SMTP_IGNORE_REJECTED_RECIPIENTS") {
config.SMTPIgnoreRejectedRecipients = true
}
if getEnabledFromEnv("MP_SMTP_DISABLE_RDNS") {
smtpd.DisableReverseDNS = true
}
@@ -328,6 +337,7 @@ func initConfigFromEnv() {
config.SMTPRelayConfig.AllowedRecipients = os.Getenv("MP_SMTP_RELAY_ALLOWED_RECIPIENTS")
config.SMTPRelayConfig.BlockedRecipients = os.Getenv("MP_SMTP_RELAY_BLOCKED_RECIPIENTS")
config.SMTPRelayConfig.PreserveMessageIDs = getEnabledFromEnv("MP_SMTP_RELAY_PRESERVE_MESSAGE_IDS")
config.SMTPRelayConfig.ForwardSMTPErrors = getEnabledFromEnv("MP_SMTP_RELAY_FWD_SMTP_ERRORS")
// SMTP forwarding
config.SMTPForwardConfigFile = os.Getenv("MP_SMTP_FORWARD_CONFIG")
@@ -346,6 +356,7 @@ func initConfigFromEnv() {
config.SMTPForwardConfig.ReturnPath = os.Getenv("MP_SMTP_FORWARD_RETURN_PATH")
config.SMTPForwardConfig.OverrideFrom = os.Getenv("MP_SMTP_FORWARD_OVERRIDE_FROM")
config.SMTPForwardConfig.To = os.Getenv("MP_SMTP_FORWARD_TO")
config.SMTPForwardConfig.ForwardSMTPErrors = getEnabledFromEnv("MP_SMTP_FORWARD_FWD_SMTP_ERRORS")
// Chaos
chaos.Enabled = getEnabledFromEnv("MP_ENABLE_CHAOS")
@@ -381,6 +392,9 @@ func initConfigFromEnv() {
if len(os.Getenv("MP_WEBHOOK_LIMIT")) > 0 {
webhook.RateLimit, _ = strconv.Atoi(os.Getenv("MP_WEBHOOK_LIMIT"))
}
if len(os.Getenv("MP_WEBHOOK_DELAY")) > 0 {
webhook.Delay, _ = strconv.Atoi(os.Getenv("MP_WEBHOOK_DELAY"))
}
// Demo mode
config.DemoMode = getEnabledFromEnv("MP_DEMO_MODE")

View File

@@ -14,8 +14,9 @@ var versionCmd = &cobra.Command{
Use: "version",
Short: "Display the current version & update information",
Long: `Display the current version & update information (if available).`,
Run: func(cmd *cobra.Command, args []string) {
Run: func(cmd *cobra.Command, _ []string) {
update, _ := cmd.Flags().GetBool("update")
noReleaseCheck, _ := cmd.Flags().GetBool("no-release-check")
if update {
// Update the application
@@ -32,23 +33,25 @@ var versionCmd = &cobra.Command{
fmt.Printf("%s %s compiled with %s on %s/%s\n",
os.Args[0], config.Version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
release, err := config.GHRUConfig.Latest()
if err != nil {
fmt.Printf("Error checking for latest release: %s\n", err)
os.Exit(1)
}
if !noReleaseCheck {
release, err := config.GHRUConfig.Latest()
if err != nil {
fmt.Printf("Error checking for latest release: %s\n", err)
os.Exit(1)
}
// The latest version is the same version
if release.Tag == config.Version {
os.Exit(0)
}
// The latest version is the same version
if release.Tag == config.Version {
os.Exit(0)
}
// A newer release is available
fmt.Printf(
"\nUpdate available: %s\nRun `%s version -u` to update (requires read/write access to install directory).\n",
release.Tag,
os.Args[0],
)
// A newer release is available
fmt.Printf(
"\nUpdate available: %s\nRun `%s version -u` to update (requires read/write access to install directory).\n",
release.Tag,
os.Args[0],
)
}
},
}
@@ -57,4 +60,6 @@ func init() {
versionCmd.Flags().
BoolP("update", "u", false, "update to latest version")
versionCmd.Flags().
Bool("no-release-check", false, "do not check online for the latest release version")
}

View File

@@ -15,6 +15,7 @@ import (
"github.com/axllent/mailpit/internal/auth"
"github.com/axllent/mailpit/internal/logger"
"github.com/axllent/mailpit/internal/smtpd/chaos"
"github.com/axllent/mailpit/internal/snakeoil"
"github.com/axllent/mailpit/internal/spamassassin"
"github.com/axllent/mailpit/internal/tools"
)
@@ -126,11 +127,15 @@ var (
// BlockRemoteCSSAndFonts used to disable remote CSS & fonts
BlockRemoteCSSAndFonts = false
// AllowInternalHTTPRequests will allow HTTP requests to internal IP addresses (e.g., loopback, private, link-local, or multicast) when set to true.
// This policy applies to both link checking and screenshot generation (proxy) features and is disabled by default for security reasons.
AllowInternalHTTPRequests = false
// CLITagsArg is used to map the CLI args
CLITagsArg string
// ValidTagRegexp represents a valid tag
ValidTagRegexp = regexp.MustCompile(`^([a-zA-Z0-9\-\ \_\.]){1,}$`)
ValidTagRegexp = regexp.MustCompile(`^([a-zA-Z0-9\-\ \_\.@]){1,100}$`)
// TagsConfig is a yaml file to pre-load tags
TagsConfig string
@@ -180,6 +185,9 @@ var (
// SMTPAllowedRecipientsRegexp is the compiled version of SMTPAllowedRecipients
SMTPAllowedRecipientsRegexp *regexp.Regexp
// SMTPIgnoreRejectedRecipients if true, will accept emails to rejected recipients with 2xx response but silently drop them
SMTPIgnoreRejectedRecipients bool
// POP3Listen address - if set then Mailpit will start the POP3 server and listen on this address
POP3Listen = "[::]:1110"
@@ -248,6 +256,7 @@ type SMTPRelayConfigStruct struct {
BlockedRecipients string `yaml:"blocked-recipients"` // regex, if set prevents relating to these addresses
BlockedRecipientsRegexp *regexp.Regexp // compiled regexp using BlockedRecipients
PreserveMessageIDs bool `yaml:"preserve-message-ids"` // preserve the original Message-ID when relaying
ForwardSMTPErrors bool `yaml:"forward-smtp-errors"` // whether to log smtp-errors or forward them to upstream-client
// DEPRECATED 2024/03/12
RecipientAllowlist string `yaml:"recipient-allowlist"`
@@ -255,18 +264,19 @@ type SMTPRelayConfigStruct struct {
// SMTPForwardConfigStruct struct for parsing yaml & storing variables
type SMTPForwardConfigStruct struct {
To string `yaml:"to"` // comma-separated list of email addresses
Host string `yaml:"host"` // SMTP host
Port int `yaml:"port"` // SMTP port
STARTTLS bool `yaml:"starttls"` // whether to use STARTTLS
TLS bool `yaml:"tls"` // whether to use TLS
AllowInsecure bool `yaml:"allow-insecure"` // allow insecure authentication, ignore TLS validation
Auth string `yaml:"auth"` // none, plain, login, cram-md5
Username string `yaml:"username"` // plain & cram-md5
Password string `yaml:"password"` // plain
Secret string `yaml:"secret"` // cram-md5
ReturnPath string `yaml:"return-path"` // allow overriding the bounce address
OverrideFrom string `yaml:"override-from"` // allow overriding of the from address
To string `yaml:"to"` // comma-separated list of email addresses
Host string `yaml:"host"` // SMTP host
Port int `yaml:"port"` // SMTP port
STARTTLS bool `yaml:"starttls"` // whether to use STARTTLS
TLS bool `yaml:"tls"` // whether to use TLS
AllowInsecure bool `yaml:"allow-insecure"` // allow insecure authentication, ignore TLS validation
Auth string `yaml:"auth"` // none, plain, login, cram-md5
Username string `yaml:"username"` // plain & cram-md5
Password string `yaml:"password"` // plain
Secret string `yaml:"secret"` // cram-md5
ReturnPath string `yaml:"return-path"` // allow overriding the bounce address
OverrideFrom string `yaml:"override-from"` // allow overriding of the from address
ForwardSMTPErrors bool `yaml:"forward-smtp-errors"` // whether to log smtp-errors or forward them to upstream-client
}
// VerifyConfig wil do some basic checking
@@ -279,7 +289,8 @@ func VerifyConfig() error {
// The default Content Security Policy is updates on every application page load to replace script-src 'self'
// with a random nonce ID to prevent XSS. This applies to the Mailpit app & API.
// See server.middleWareFunc()
ContentSecurityPolicy = fmt.Sprintf("default-src 'self'; script-src 'self'; style-src %s 'unsafe-inline'; frame-src 'self'; img-src * data: blob:; font-src %s data:; media-src 'self'; connect-src 'self' ws: wss:; object-src 'none'; base-uri 'self';",
ContentSecurityPolicy = fmt.Sprintf(
"default-src 'self'; script-src 'self'; style-src %s 'unsafe-inline'; frame-src 'self'; img-src * data: blob:; font-src %s data:; media-src 'self'; connect-src 'self' ws: wss:; object-src 'none'; base-uri 'self';",
cssFontRestriction, cssFontRestriction,
)
@@ -333,8 +344,19 @@ func VerifyConfig() error {
}
if UITLSCert != "" {
UITLSCert = filepath.Clean(UITLSCert)
UITLSKey = filepath.Clean(UITLSKey)
if strings.HasPrefix(UITLSCert, "sans:") {
// generate a self-signed certificate
UITLSCert = snakeoil.Public(UITLSCert)
} else {
UITLSCert = filepath.Clean(UITLSCert)
}
if strings.HasPrefix(UITLSKey, "sans:") {
// generate a self-signed key
UITLSKey = snakeoil.Private(UITLSKey)
} else {
UITLSKey = filepath.Clean(UITLSKey)
}
if !isFile(UITLSCert) {
return fmt.Errorf("[ui] TLS certificate not found or readable: %s", UITLSCert)
@@ -393,8 +415,19 @@ func VerifyConfig() error {
}
if SMTPTLSCert != "" {
SMTPTLSCert = filepath.Clean(SMTPTLSCert)
SMTPTLSKey = filepath.Clean(SMTPTLSKey)
if strings.HasPrefix(SMTPTLSCert, "sans:") {
// generate a self-signed certificate
SMTPTLSCert = snakeoil.Public(SMTPTLSCert)
} else {
SMTPTLSCert = filepath.Clean(SMTPTLSCert)
}
if strings.HasPrefix(SMTPTLSKey, "sans:") {
// generate a self-signed key
SMTPTLSKey = snakeoil.Private(SMTPTLSKey)
} else {
SMTPTLSKey = filepath.Clean(SMTPTLSKey)
}
if !isFile(SMTPTLSCert) {
return fmt.Errorf("[smtp] TLS certificate not found or readable: %s", SMTPTLSCert)
@@ -462,8 +495,18 @@ func VerifyConfig() error {
// POP3 server
if POP3TLSCert != "" {
POP3TLSCert = filepath.Clean(POP3TLSCert)
POP3TLSKey = filepath.Clean(POP3TLSKey)
if strings.HasPrefix(POP3TLSCert, "sans:") {
// generate a self-signed certificate
POP3TLSCert = snakeoil.Public(POP3TLSCert)
} else {
POP3TLSCert = filepath.Clean(POP3TLSCert)
}
if strings.HasPrefix(POP3TLSKey, "sans:") {
// generate a self-signed key
POP3TLSKey = snakeoil.Private(POP3TLSKey)
} else {
POP3TLSKey = filepath.Clean(POP3TLSKey)
}
if !isFile(POP3TLSCert) {
return fmt.Errorf("[pop3] TLS certificate not found or readable: %s", POP3TLSCert)
@@ -548,6 +591,14 @@ func VerifyConfig() error {
logger.Log().Infof("[smtp] only allowing recipients matching regexp: %s", SMTPAllowedRecipients)
}
if SMTPIgnoreRejectedRecipients {
if SMTPAllowedRecipientsRegexp == nil {
logger.Log().Warn("[smtp] ignoring rejected recipients has no effect without setting smtp-allowed-recipients")
} else {
logger.Log().Info("[smtp] ignoring rejected recipients")
}
}
if err := parseRelayConfig(SMTPRelayConfigFile); err != nil {
return err
}
@@ -571,8 +622,10 @@ func VerifyConfig() error {
}
SMTPRelayMatchingRegexp = re
logger.Log().Infof("[relay] auto-relaying new messages to recipients matching \"%s\" via %s:%d",
SMTPRelayMatching, SMTPRelayConfig.Host, SMTPRelayConfig.Port)
logger.Log().Infof(
"[relay] auto-relaying new messages to recipients matching \"%s\" via %s:%d",
SMTPRelayMatching, SMTPRelayConfig.Host, SMTPRelayConfig.Port,
)
}
}

View File

@@ -1,34 +1,76 @@
import eslintConfigPrettier from "eslint-config-prettier/flat";
import neostandard, { resolveIgnoresFromGitignore } from "neostandard";
import globals from "globals";
import { includeIgnoreFile } from "@eslint/compat";
import js from "@eslint/js";
import vue from "eslint-plugin-vue";
import { fileURLToPath } from "node:url";
const gitignorePath = fileURLToPath(new URL(".gitignore", import.meta.url));
export default [
/* Baseline JS rules, provided by Neostandard */
...neostandard({
/* Allows references to browser APIs like `document` */
env: ["browser"],
/* Use .gitignore to prevent linting of irrelevant files */
includeIgnoreFile(gitignorePath, ".gitignore"),
/* We rely on .gitignore to avoid running against dist / dependency files */
ignores: resolveIgnoresFromGitignore(),
/* Disables a range of style-related rules, as we use Prettier for that */
noStyle: true,
/* Ensures we only lint JS and Vue files */
/* ESLint's recommended rules */
{
files: ["**/*.js", "**/*.vue"],
}),
languageOptions: { globals: { ...globals.browser, ...globals.node } },
rules: js.configs.recommended.rules,
},
/* Vue-specific rules */
...vue.configs["flat/recommended"],
/* Prettier is responsible for formatting, so this disables any conflicting rules */
/* Prettier is responsible for formatting, so we disable conflicting rules */
eslintConfigPrettier,
/* Our custom rules */
{
rules: {
/* We prefer arrow functions for tidiness and consistency */
/* Always use arrow functions for tidiness and consistency */
"prefer-arrow-callback": "error",
/* Always use camelCase for variable names */
camelcase: [
"error",
{
ignoreDestructuring: false,
ignoreGlobals: true,
ignoreImports: false,
properties: "never",
},
],
/* The default case in switch statements must always be last */
"default-case-last": "error",
/* Always use dot notation where possible (e.g. `obj.val` over `obj['val']`) */
"dot-notation": "error",
/* Always use `===` and `!==` for comparisons unless unambiguous */
eqeqeq: ["error", "smart"],
/* Never use `eval()` as it violates our CSP and can lead to security issues */
"no-eval": "error",
"no-implied-eval": "error",
/* Prevents accidental use of template literals in plain strings, e.g. "my ${var}" */
"no-template-curly-in-string": "error",
/* Avoid unnecessary ternary operators */
"no-unneeded-ternary": "error",
/* Avoid unused expressions that have no purpose */
"no-unused-expressions": "error",
/* Always use `const` or `let` to make scope behaviour clear */
"no-var": "error",
/* Always use shorthand syntax for objects where possible, e.g. { a, b() { } } */
"object-shorthand": "error",
/* Always use `const` for variables that are never reassigned */
"prefer-const": "error",
},
},
];

76
go.mod
View File

@@ -1,34 +1,35 @@
module github.com/axllent/mailpit
go 1.24.3
go 1.25.0
require (
github.com/PuerkitoBio/goquery v1.10.3
github.com/PuerkitoBio/goquery v1.11.0
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
github.com/axllent/ghru/v2 v2.0.1
github.com/axllent/semver v0.0.1
github.com/goccy/go-yaml v1.18.0
github.com/gomarkdown/markdown v0.0.0-20250311123330-531bef5e742b
github.com/axllent/ghru/v2 v2.1.0
github.com/axllent/semver v1.0.0
github.com/goccy/go-yaml v1.19.2
github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab
github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.3
github.com/jhillyerd/enmime/v2 v2.2.0
github.com/klauspost/compress v1.18.0
github.com/kovidgoyal/imaging v1.6.4
github.com/jhillyerd/enmime/v2 v2.3.0
github.com/klauspost/compress v1.18.4
github.com/kovidgoyal/imaging v1.8.20
github.com/leporo/sqlf v1.4.0
github.com/lithammer/shortuuid/v4 v4.2.0
github.com/mneis/go-telnet v0.0.0-20221017141824-6f643e477c62
github.com/prometheus/client_golang v1.22.0
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.23.2
github.com/rqlite/gorqlite v0.0.0-20250609141355-ac86a4a1c9a8
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.9.1
github.com/spf13/pflag v1.0.6
github.com/sirupsen/logrus v1.9.4
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
github.com/tg123/go-htpasswd v1.2.4
github.com/vanng822/go-premailer v1.25.0
golang.org/x/crypto v0.39.0
golang.org/x/net v0.41.0
golang.org/x/text v0.26.0
golang.org/x/time v0.12.0
modernc.org/sqlite v1.38.0
github.com/vanng822/go-premailer v1.31.0
golang.org/x/crypto v0.48.0
golang.org/x/net v0.50.0
golang.org/x/text v0.34.0
golang.org/x/time v0.14.0
modernc.org/sqlite v1.46.1
)
require (
@@ -37,37 +38,44 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/clipperhouse/displaywidth v0.11.0 // indirect
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/inbucket/html2text v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kovidgoyal/go-parallel v1.1.1 // indirect
github.com/kovidgoyal/go-shm v1.0.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mattn/go-runewidth v0.0.20 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/olekukonko/errors v1.1.0 // indirect
github.com/olekukonko/ll v0.0.9 // indirect
github.com/olekukonko/tablewriter v1.0.7 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect
github.com/olekukonko/errors v1.2.0 // indirect
github.com/olekukonko/ll v0.1.7 // indirect
github.com/olekukonko/tablewriter v1.1.3 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.65.0 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/procfs v0.19.2 // indirect
github.com/reiver/go-oi v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/vanng822/css v1.0.1 // indirect
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
golang.org/x/image v0.28.0 // indirect
golang.org/x/mod v0.25.0 // indirect
golang.org/x/sys v0.33.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
modernc.org/libc v1.66.1 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect
golang.org/x/image v0.36.0 // indirect
golang.org/x/mod v0.33.0 // indirect
golang.org/x/sys v0.41.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
modernc.org/libc v1.68.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
)

189
go.sum
View File

@@ -1,22 +1,27 @@
github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5 h1:IEjq88XO4PuBDcvmjQJcQGg+w+UaafSy8G5Kcb5tBhI=
github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5/go.mod h1:exZ0C/1emQJAw5tHOaUDyY1ycttqBAPcxuzf7QbY6ec=
github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo=
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw=
github.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ=
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
github.com/axllent/ghru/v2 v2.0.1 h1:/9XHbMqJRGRxlyNMq2XiHQpBLz7hlq8xCdgJ4ZhjCoM=
github.com/axllent/ghru/v2 v2.0.1/go.mod h1:seMMjx8/0r5ZAL7c0vwTPIRoyN0AoTUqAylZEWZWGK4=
github.com/axllent/semver v0.0.1 h1:QqF+KSGxgj8QZzSXAvKFqjGWE5792ksOnQhludToK8E=
github.com/axllent/semver v0.0.1/go.mod h1:2xSPzvG8n9mRfdtxSvWvfTfQGWfHsMsHO1iZnKATMSc=
github.com/axllent/ghru/v2 v2.1.0 h1:zNW96KO+rmXggizZhHzIX7MExOiV4jx+63Y9nXlwLV0=
github.com/axllent/ghru/v2 v2.1.0/go.mod h1:8l7s1phdc375vvf8LHxT7wnJqXlThdHJR5EBtHNWhTg=
github.com/axllent/semver v1.0.0 h1:FDekA0alnMed5bWVWjUwBS+6QouZZkmPXsGVmOfjWOg=
github.com/axllent/semver v1.0.0/go.mod h1:ySHHYLyFX3vKAALmaO8TOOJkzGRsUNmzFiIWwPm8li8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a h1:MISbI8sU/PSK/ztvmWKFcI7UGb5/HQT7B+i3a2myKgI=
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a/go.mod h1:2GxOXOlEPAMFPfp014mK1SWq8G8BN8o7/dfYqJrVGn8=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=
github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -26,12 +31,14 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs=
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
github.com/gomarkdown/markdown v0.0.0-20250311123330-531bef5e742b h1:EY/KpStFl60qA17CptGXhwfZ+k1sFNJIUNR8DdbcuUk=
github.com/gomarkdown/markdown v0.0.0-20250311123330-531bef5e742b/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab h1:VYNivV7P8IRHUam2swVUNkhIdp0LRRFKe4hXNnoZKTc=
github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
@@ -45,16 +52,26 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/inbucket/html2text v1.0.0 h1:N5kza++4uBBDJ2Z3KUnTRyPNoBcW+YfOgNiNmNB+sgs=
github.com/inbucket/html2text v1.0.0/go.mod h1:5TrhXQKGU+LXurODaSm55Y9eXoPBRnYiOz4x2XfUoJU=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jhillyerd/enmime/v2 v2.2.0 h1:Pe35MB96eZK5Q0XjlvPftOgWypQpd1gcbfJKAt7rsB8=
github.com/jhillyerd/enmime/v2 v2.2.0/go.mod h1:SOBXlCemjhiV2DvHhAKnJiWrtJGS/Ffuw4Iy7NjBTaI=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kovidgoyal/imaging v1.6.4 h1:K0idhRPXnRrJBKnBYcTfI1HTWSNDeAn7hYDvf9I0dCk=
github.com/kovidgoyal/imaging v1.6.4/go.mod h1:bEIgsaZmXlvFfkv/CUxr9rJook6AQkJnpB5EPosRfRY=
github.com/jhillyerd/enmime/v2 v2.3.0 h1:Y/pzQanyU8nkSgB2npXX8Dha5OItJE/QwbDJM4sf/kU=
github.com/jhillyerd/enmime/v2 v2.3.0/go.mod h1:mGKXAP45l6pF6HZiaLhgSYsgteJskaSIYmEZXpw6ZpI=
github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/kovidgoyal/go-parallel v1.1.1 h1:1OzpNjtrUkBPq3UaqrnvOoB2F9RttSt811uiUXyI7ok=
github.com/kovidgoyal/go-parallel v1.1.1/go.mod h1:BJNIbe6+hxyFWv7n6oEDPj3PA5qSw5OCtf0hcVxWJiw=
github.com/kovidgoyal/go-shm v1.0.0 h1:HJEel9D1F9YhULvClEHJLawoRSj/1u/EDV7MJbBPgQo=
github.com/kovidgoyal/go-shm v1.0.0/go.mod h1:Yzb80Xf9L3kaoB2RGok9hHwMIt7Oif61kT6t3+VnZds=
github.com/kovidgoyal/imaging v1.8.20 h1:74GZ7C2rIm3rqmGEjK1GvvPOOnJ0SS5iDOa6Flfo0b0=
github.com/kovidgoyal/imaging v1.8.20/go.mod h1:d3phGYkTChGYkY4y++IjpHgUGhWGELDc2NEQAqxwZZg=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leporo/sqlf v1.4.0 h1:SyWnX/8GSGOzVmanG0Ub1c04mR9nNl6Tq3IeFKX2/4c=
@@ -66,52 +83,56 @@ github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stg
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ=
github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mneis/go-telnet v0.0.0-20221017141824-6f643e477c62 h1:XMG5DklHoioVYysfYglOB7vRBg/LOUJZy2mq2QyedLg=
github.com/mneis/go-telnet v0.0.0-20221017141824-6f643e477c62/go.mod h1:niAM5cni0I/47IFA995xQfeK58Mkbb7FHJjacY4OGQg=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
github.com/olekukonko/tablewriter v1.0.7 h1:HCC2e3MM+2g72M81ZcJU11uciw6z/p82aEnm4/ySDGw=
github.com/olekukonko/tablewriter v1.0.7/go.mod h1:H428M+HzoUXC6JU2Abj9IT9ooRmdq9CxuDmKMtrOCMs=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc=
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0=
github.com/olekukonko/errors v1.2.0 h1:10Zcn4GeV59t/EGqJc8fUjtFT/FuUh5bTMzZ1XwmCRo=
github.com/olekukonko/errors v1.2.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
github.com/olekukonko/ll v0.1.7 h1:WyK1YZwOTUKHEXZz3VydBDT5t3zDqa9yI8iJg5PHon4=
github.com/olekukonko/ll v0.1.7/go.mod h1:RPRC6UcscfFZgjo1nulkfMH5IM0QAYim0LfnMvUuozw=
github.com/olekukonko/tablewriter v1.1.3 h1:VSHhghXxrP0JHl+0NnKid7WoEmd9/urKRJLysb70nnA=
github.com/olekukonko/tablewriter v1.1.3/go.mod h1:9VU0knjhmMkXjnMKrZ3+L2JhhtsQ/L38BbL3CRNE8tM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
github.com/reiver/go-oi v1.0.0 h1:nvECWD7LF+vOs8leNGV/ww+F2iZKf3EYjYZ527turzM=
github.com/reiver/go-oi v1.0.0/go.mod h1:RrDBct90BAhoDTxB1fenZwfykqeGvhI6LsNfStJoEkI=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/rqlite/gorqlite v0.0.0-20250609141355-ac86a4a1c9a8 h1:BoxiqWvhprOB2isgM59s8wkgKwAoyQH66Twfmof41oE=
github.com/rqlite/gorqlite v0.0.0-20250609141355-ac86a4a1c9a8/go.mod h1:xF/KoXmrRyahPfo5L7Szb5cAAUl53dMWBh9cMruGEZg=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -121,36 +142,41 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tg123/go-htpasswd v1.2.4 h1:HgH8KKCjdmo7jjXWN9k1nefPBd7Be3tFCTjc2jPraPU=
github.com/tg123/go-htpasswd v1.2.4/go.mod h1:EKThQok9xHkun6NBMynNv6Jmu24A33XdZzzl4Q7H1+0=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/vanng822/css v1.0.1 h1:10yiXc4e8NI8ldU6mSrWmSWMuyWgPr9DZ63RSlsgDw8=
github.com/vanng822/css v1.0.1/go.mod h1:tcnB1voG49QhCrwq1W0w5hhGasvOg+VQp9i9H1rCM1w=
github.com/vanng822/go-premailer v1.25.0 h1:hGHKfroCXrCDTyGVR8o4HCON5/HWvc7C1uocS+VnaZs=
github.com/vanng822/go-premailer v1.25.0/go.mod h1:8WJKIPZtegxqSOA8+eDFx7QNesKmMYfGEIodLTJqrtM=
github.com/vanng822/go-premailer v1.31.0 h1:r1a1WH2I5NnGMhrmjVZyYhY0ThvaamKBkS2UuM91Fuo=
github.com/vanng822/go-premailer v1.31.0/go.mod h1:hzI26/YvzUADrxqifxGLJvNvn3tWBU6VMHRvxsskpuo=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
golang.org/x/image v0.28.0 h1:gdem5JW1OLS4FbkWgLO+7ZeFzYtL3xClb97GaUzYMFE=
golang.org/x/image v0.28.0/go.mod h1:GUJYXtnGKEUgggyzh+Vxt+AviiCcyiwpsl8iQ8MvwGY=
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -160,8 +186,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -169,13 +195,12 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -184,8 +209,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -204,37 +229,41 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
modernc.org/cc/v4 v4.26.1 h1:+X5NtzVBn0KgsBCBe+xkDC7twLb/jNVj9FPgiwSQO3s=
modernc.org/cc/v4 v4.26.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE=
modernc.org/fileutil v1.3.3 h1:3qaU+7f7xxTUmvU1pJTZiDLAIoJVdUSSauJNHg9yXoA=
modernc.org/fileutil v1.3.3/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=
modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.30.2 h1:4yPaaq9dXYXZ2V8s1UgrC3KIj580l2N4ClrLwnbv2so=
modernc.org/ccgo/v4 v4.30.2/go.mod h1:yZMnhWEdW0qw3EtCndG1+ldRrVGS+bIwyWmAWzS0XEw=
modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA=
modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/goabi0 v0.0.3 h1:y81b9r3asCh6Xtse6Nz85aYGB0cG3M3U6222yap1KWI=
modernc.org/goabi0 v0.0.3/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
modernc.org/libc v1.66.1 h1:4uQsntXbVyAgrV+j6NhKvDiUypoJL48BWQx6sy9y8ok=
modernc.org/libc v1.66.1/go.mod h1:AiZxInURfEJx516LqEaFcrC+X38rt9G7+8ojIXQKHbo=
modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo=
modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
modernc.org/libc v1.68.0 h1:PJ5ikFOV5pwpW+VqCK1hKJuEWsonkIJhhIXyuF/91pQ=
modernc.org/libc v1.68.0/go.mod h1:NnKCYeoYgsEqnY3PgvNgAeaJnso968ygU8Z0DxjoEc0=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
@@ -243,8 +272,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.38.0 h1:+4OrfPQ8pxHKuWG4md1JpR/EYAh3Md7TdejuuzE7EUI=
modernc.org/sqlite v1.38.0/go.mod h1:1Bj+yES4SVvBZ4cBOpVZ6QgesMCKpJZDq0nxYzOpmNE=
modernc.org/sqlite v1.46.1 h1:eFJ2ShBLIEnUWlLy12raN0Z1plqmFX9Qe3rjQTKt6sU=
modernc.org/sqlite v1.46.1/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=

View File

@@ -15,7 +15,7 @@ done
OS=
case "$(uname -s)" in
Linux) OS="linux" ;;
Darwin) OS="Darwin" ;;
Darwin) OS="darwin" ;;
*)
echo "OS not supported."
exit 2

View File

@@ -1,6 +1,6 @@
{
"api_version":"1.0.4",
"last_update_date":"2025-06-12 18:27:28 +0000",
"last_update_date":"2026-02-16 15:39:06 +0000",
"nicenames":{"family":{"gmail":"Gmail","outlook":"Outlook","yahoo":"Yahoo! Mail","apple-mail":"Apple Mail","aol":"AOL","thunderbird":"Mozilla Thunderbird","microsoft":"Microsoft","samsung-email":"Samsung Email","sfr":"SFR","orange":"Orange","protonmail":"ProtonMail","hey":"HEY","mail-ru":"Mail.ru","fastmail":"Fastmail","laposte":"LaPoste.net","t-online-de":"T-online.de","free-fr":"Free.fr","gmx":"GMX","web-de":"WEB.DE","ionos-1and1":"1&1","rainloop":"RainLoop","wp-pl":"WP.pl"},"platform":{"desktop-app":"Desktop","desktop-webmail":"Desktop Webmail","mobile-webmail":"Mobile Webmail","webmail":"Webmail","ios":"iOS","android":"Android","windows":"Windows","macos":"macOS","windows-mail":"Windows Mail","outlook-com":"Outlook.com"},"support":{"supported":"Supported","mitigated":"Partially supported","unsupported":"Not supported","unknown":"Support unknown","mixed":"Mixed support"},"category":{"html":"HTML","css":"CSS","image":"Image formats","others":"Others"}},
"data":[
{
@@ -110,7 +110,7 @@
"last_test_date":"2023-12-19",
"test_url":"https://www.caniemail.com/tests/css-font-face.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/veY9MhuhgFeF1ly5crrhTXawfLJSwxgpYi27OElI7iSoc/list",
"stats":{"apple-mail":{"macos":{"12.2":"y"},"ios":{"10.3":"y","12.3.1":"y"}},"gmail":{"desktop-webmail":{"2019-07":"n #6"},"ios":{"2019-07":"n"},"android":{"2019-07":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-05":"a #2","2021-03":"n #7","2024-03":"n"},"ios":{"2019-07":"y","2024-03":"n"},"android":{"2019-07":"a #1","2024-04":"n"}},"outlook":{"windows":{"2003":"a #3","2007":"a #4 #5","2010":"a #4 #5","2013":"a #4 #5","2016":"a #4 #5","2019":"a #4"},"windows-mail":{"2020-01":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2019-07":"n","2023-12":"n"},"ios":{"2.51.1":"y","3.29.0":"n"},"android":{"2019-07":"n"}},"samsung-email":{"android":{"6.0":"y #8","2021-11":"y #8"}},"sfr":{"desktop-webmail":{"2019-07":"a #2"},"ios":{"2019-07":"n"},"android":{"2019-07":"n"}},"thunderbird":{"macos":{"60.7":"y","78.5":"y"}},"aol":{"desktop-webmail":{"2020-01":"n"},"ios":{"2020-01":"n"},"android":{"2020-01":"n"}},"yahoo":{"desktop-webmail":{"2019-07":"n"},"ios":{"2019-07":"n"},"android":{"2019-07":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"n"}},"laposte":{"desktop-webmail":{"2021-08":"a #2"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"n"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"n"}}},
"stats":{"apple-mail":{"macos":{"12.2":"y"},"ios":{"10.3":"y","12.3.1":"y"}},"gmail":{"desktop-webmail":{"2019-07":"n #6"},"ios":{"2019-07":"n"},"android":{"2019-07":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-05":"a #2","2021-03":"n #7","2024-03":"n"},"ios":{"2019-07":"y","2024-03":"n"},"android":{"2019-07":"a #1","2024-04":"n"}},"outlook":{"windows":{"2003":"a #3","2007":"a #4 #5","2010":"a #4 #5","2013":"a #4 #5","2016":"a #4 #5","2019":"a #4"},"windows-mail":{"2020-01":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2019-07":"n","2023-12":"n"},"ios":{"2.51.1":"y","3.29.0":"n"},"android":{"2019-07":"n"}},"samsung-email":{"android":{"6.0":"y #8","2021-11":"y #8"}},"sfr":{"desktop-webmail":{"2019-07":"a #2","2025-07":"n"},"ios":{"2019-07":"n"},"android":{"2019-07":"n"}},"thunderbird":{"macos":{"60.7":"y","78.5":"y"}},"aol":{"desktop-webmail":{"2020-01":"n"},"ios":{"2020-01":"n"},"android":{"2020-01":"n"}},"yahoo":{"desktop-webmail":{"2019-07":"n"},"ios":{"2019-07":"n"},"android":{"2019-07":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"n"}},"laposte":{"desktop-webmail":{"2021-08":"a #2","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"n"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"n"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported through a `<link>` tag.","2":"Partial. Only supported directly through a `<style>` tag.","3":"Buggy. Support depends on the version of IE installed.","4":"Partial. The declaration is supported but distant fonts are ignored.","5":"Buggy. Elements using a font declared with `@font-face` ignore the font stack and fall back to Times New Roman. Use `mso-generic-font-family` and `mso-font-alt` to control the fallback.","6":"Not supported. Roboto and Google Sans can be used, but only because they're embedded with the webmail's own styles.","7":"Not supported. The `@font-face` declaration is kept but the `src` property is removed.","8":"Not supported when using a Microsoft email address; outlook, live, hotmail, etc."}
},
@@ -126,7 +126,7 @@
"last_test_date":"2019-02-28",
"test_url":"https://www.caniemail.com/tests/css-placement.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/6vV9sx4RoRsdnkZBDjLWwSC18VcUQzJY00tlj2NVSxKKv/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"12.1":"y"}},"gmail":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-08":"n","2021-03":"n"},"ios":{"2019-08":"y","2023-12":"n"},"android":{"2019-08":"y","2023-12":"n"}},"outlook":{"windows":{"2007":"y","2010":"y","2013":"y","2016":"y","2019":"y"},"windows-mail":{"2019-02":"y"},"macos":{"2019-02":"y","16.80":"n"},"outlook-com":{"2019-02":"n","2023-12":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"}},"thunderbird":{"macos":{"60.8":"y","78.5":"n"}},"yahoo":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"}},"aol":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2020-01":"n"}},"samsung-email":{"android":{"5.0.10.2":"n"}},"sfr":{"desktop-webmail":{"2019-08":"n"},"ios":{"2019-08":"n"},"android":{"2019-08":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"n"}},"laposte":{"desktop-webmail":{"2021-08":"n"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"n"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"n"}},"wp-pl":{"desktop-webmail":{"2023-12":"n"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"12.1":"y"}},"gmail":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-08":"n","2021-03":"n"},"ios":{"2019-08":"y","2023-12":"n"},"android":{"2019-08":"y","2023-12":"n"}},"outlook":{"windows":{"2007":"y","2010":"y","2013":"y","2016":"y","2019":"y"},"windows-mail":{"2019-02":"y"},"macos":{"2019-02":"y","16.80":"n"},"outlook-com":{"2019-02":"n","2023-12":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"}},"thunderbird":{"macos":{"60.8":"y","78.5":"n"}},"yahoo":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"}},"aol":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2020-01":"n"}},"samsung-email":{"android":{"5.0.10.2":"n"}},"sfr":{"desktop-webmail":{"2019-08":"n","2025-07":"n"},"ios":{"2019-08":"n"},"android":{"2019-08":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"n"}},"laposte":{"desktop-webmail":{"2021-08":"n","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"n"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"n"}},"wp-pl":{"desktop-webmail":{"2023-12":"n"}}},
"notes":null,
"notes_by_num":null
},
@@ -142,7 +142,7 @@
"last_test_date":"2021-05-25",
"test_url":"https://www.caniemail.com/tests/css-animation.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/u4oWccYOFNNyTagHs2NSUZqJYQ3MssrqDMocBnRa35hf7/list",
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"13":"y"}},"gmail":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"},"mobile-webmail":{"2021-05":"n"}},"orange":{"desktop-webmail":{"2021-05":"n #1"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2021-05":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"samsung-email":{"android":{"6.1":"y"}},"sfr":{"desktop-webmail":{"2021-05":"a #1"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"thunderbird":{"macos":{"78.10":"y"}},"aol":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"yahoo":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"protonmail":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"hey":{"desktop-webmail":{"2021-05":"y"}},"mail-ru":{"desktop-webmail":{"2021-05":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"a #1"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"a #2"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"13":"y"}},"gmail":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"},"mobile-webmail":{"2021-05":"n"}},"orange":{"desktop-webmail":{"2021-05":"n #1"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2021-05":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"samsung-email":{"android":{"6.1":"y"}},"sfr":{"desktop-webmail":{"2021-05":"a #1","2025-07":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"thunderbird":{"macos":{"78.10":"y"}},"aol":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"yahoo":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"protonmail":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"hey":{"desktop-webmail":{"2021-05":"y"}},"mail-ru":{"desktop-webmail":{"2021-05":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"a #1","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"a #2"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Not supported. The `@keyframes` declaration is kept but values are incorrectly prefixed.","2":"Partial. Only supports from and to keyframes. Does not support % keyframes"}
},
@@ -158,7 +158,7 @@
"last_test_date":"2019-08-20",
"test_url":"https://www.caniemail.com/tests/css-media.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/hMLCNCSKZYHkLgLOpIWltlnYjtagbNsrwzMxalc2VbghN/list",
"stats":{"apple-mail":{"macos":{"10.3":"y"},"ios":{"10.3":"y","12.2":"y"}},"gmail":{"desktop-webmail":{"2019-08":"n"},"ios":{"2019-08":"n"},"android":{"2019-08":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-08":"y #1","2021-03":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-01":"n"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-08":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"samsung-email":{"android":{"5.0.10.2":"y","6.0":"y"}},"sfr":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"n"},"android":{"2019-08":"n"}},"thunderbird":{"macos":{"60.3":"n","78.5":"n"}},"yahoo":{"desktop-webmail":{"2019-08":"n"},"ios":{"2019-08":"n"},"android":{"2019-08":"n"}},"aol":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"10.3":"y"},"ios":{"10.3":"y","12.2":"y"}},"gmail":{"desktop-webmail":{"2019-08":"n"},"ios":{"2019-08":"n"},"android":{"2019-08":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-08":"y #1","2021-03":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-01":"n"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-08":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"samsung-email":{"android":{"5.0.10.2":"y","6.0":"y"}},"sfr":{"desktop-webmail":{"2019-08":"y","2025-07":"n"},"ios":{"2019-08":"n"},"android":{"2019-08":"n"}},"thunderbird":{"macos":{"60.3":"n","78.5":"n"}},"yahoo":{"desktop-webmail":{"2019-08":"n"},"ios":{"2019-08":"n"},"android":{"2019-08":"n"}},"aol":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Buggy. The first rule inside a media query is not prefixed."}
},
@@ -174,7 +174,7 @@
"last_test_date":"2022-08-29",
"test_url":"https://www.caniemail.com/tests/css-media-hover.html",
"test_results_url":"https://testi.at/proj/onECpNVH8Dhv7BSLPXUbQ4s0O",
"stats":{"apple-mail":{"macos":{"2022-08":"y"},"ios":{"2022-08":"y"}},"gmail":{"desktop-webmail":{"2022-08":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"},"mobile-webmail":{"2022-08":"n"}},"orange":{"desktop-webmail":{"2022-08":"u"},"ios":{"2022-08":"u"},"android":{"2022-08":"u"}},"outlook":{"windows":{"2022-08":"n"},"windows-mail":{"2022-08":"n"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2022-08":"y"},"ios":{"2022-08":"y"},"android":{"2022-08":"y"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"n"},"android":{"2024-03":"n"}},"thunderbird":{"macos":{"2022-08":"u"}},"aol":{"desktop-webmail":{"2022-08":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"}},"yahoo":{"desktop-webmail":{"2022-08":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"}},"protonmail":{"desktop-webmail":{"2022-08":"u"},"ios":{"2022-08":"u"},"android":{"2022-08":"u"}},"hey":{"desktop-webmail":{"2022-08":"u"}},"mail-ru":{"desktop-webmail":{"2022-08":"n"}},"fastmail":{"desktop-webmail":{"2022-08":"u"}},"laposte":{"desktop-webmail":{"2022-08":"u"}}},
"stats":{"apple-mail":{"macos":{"2022-08":"y"},"ios":{"2022-08":"y"}},"gmail":{"desktop-webmail":{"2022-08":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"},"mobile-webmail":{"2022-08":"n"}},"orange":{"desktop-webmail":{"2022-08":"u"},"ios":{"2022-08":"u"},"android":{"2022-08":"u"}},"outlook":{"windows":{"2022-08":"n"},"windows-mail":{"2022-08":"n"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2022-08":"y"},"ios":{"2022-08":"y"},"android":{"2022-08":"y"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y","2025-07":"n"},"ios":{"2024-03":"n"},"android":{"2024-03":"n"}},"thunderbird":{"macos":{"2022-08":"u"}},"aol":{"desktop-webmail":{"2022-08":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"}},"yahoo":{"desktop-webmail":{"2022-08":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"}},"protonmail":{"desktop-webmail":{"2022-08":"y"},"ios":{"2022-08":"y"},"android":{"2022-08":"y"}},"hey":{"desktop-webmail":{"2022-08":"u"}},"mail-ru":{"desktop-webmail":{"2022-08":"n"}},"fastmail":{"desktop-webmail":{"2022-08":"u"}},"laposte":{"desktop-webmail":{"2022-08":"u","2025-07":"n"}}},
"notes":null,
"notes_by_num":null
},
@@ -190,7 +190,7 @@
"last_test_date":"2019-08-20",
"test_url":"https://www.caniemail.com/tests/css-media.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/hMLCNCSKZYHkLgLOpIWltlnYjtagbNsrwzMxalc2VbghN/list",
"stats":{"apple-mail":{"macos":{"10.3":"y"},"ios":{"10.3":"n","12":"y","13":"y","15":"y","18.3.2":"a #2"}},"gmail":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"y","2025-04":"n"},"android":{"2019-08":"y"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-08":"y #1","2021-03":"y","2024-04":"y"},"ios":{"2019-08":"n","2024-04":"y"},"android":{"2019-08":"y","2024-04":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-01":"n"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-08":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"samsung-email":{"android":{"5.0.10.2":"n","6.0":"y"}},"sfr":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"n"},"android":{"2019-08":"n"}},"thunderbird":{"macos":{"60.3":"y","78.5":"n"}},"yahoo":{"desktop-webmail":{"2019-08":"n"},"ios":{"2019-08":"n"},"android":{"2019-08":"n"}},"aol":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"10.3":"y"},"ios":{"10.3":"n","12":"y","13":"y","15":"y","18.3.2":"a #2"}},"gmail":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"y","2025-04":"n"},"android":{"2019-08":"y"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-08":"y #1","2021-03":"y","2024-04":"y"},"ios":{"2019-08":"n","2024-04":"y"},"android":{"2019-08":"y","2024-04":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-01":"n"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-08":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"samsung-email":{"android":{"5.0.10.2":"n","6.0":"y"}},"sfr":{"desktop-webmail":{"2019-08":"y","2025-07":"n"},"ios":{"2019-08":"n"},"android":{"2019-08":"n"}},"thunderbird":{"macos":{"60.3":"y","78.5":"n"}},"yahoo":{"desktop-webmail":{"2019-08":"n"},"ios":{"2019-08":"n"},"android":{"2019-08":"n"}},"aol":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Buggy. The first rule inside a media query is not prefixed.","2":"Partial. `orientation:portrait` is not supported."}
},
@@ -206,7 +206,7 @@
"last_test_date":"2023-03-08",
"test_url":"https://www.caniemail.com/tests/css-media-prefers-color-scheme.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/CBhafIa5yXDRKQKbV442rVFISXim84wMgXaoCqVFD8VTe/list",
"stats":{"apple-mail":{"macos":{"10.3":"n","12.4":"y","16.0":"y"},"ios":{"12.2":"n","13.0":"y","16.1":"y"}},"gmail":{"desktop-webmail":{"2020-01":"n","2022-12":"n"},"ios":{"2020-01":"n","2022-12":"n"},"android":{"2020-01":"n","2022-12":"n"},"mobile-webmail":{"2020-02":"n","2022-12":"n"}},"orange":{"desktop-webmail":{"2019-08":"y","2021-03":"y","2022-12":"y","2024-04":"y"},"ios":{"2020-01":"n","2022-12":"y","2024-04":"y"},"android":{"2020-01":"n","2022-12":"n","2024-04":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-01":"n"},"macos":{"2019":"y","16.70":"y #3","16.80":"y #3"},"outlook-com":{"2019-07":"y","2022-12":"y #3"},"ios":{"2020-01":"y","2022-12":"y #3"},"android":{"2020-01":"n","2022-12":"n #3","2023-03":"y #3"}},"samsung-email":{"android":{"6.0":"n","6.1":"y"}},"sfr":{"desktop-webmail":{"2019-08":"y","2022-12":"y"},"ios":{"2019-08":"n","2022-12":"n"},"android":{"2019-08":"n","2022-12":"n"}},"thunderbird":{"macos":{"60.8":"n","68.4":"y","78.5":"n","91.13":"n"}},"aol":{"desktop-webmail":{"2020-01":"n #1"},"ios":{"2020-01":"n #1"},"android":{"2020-01":"n #1"}},"yahoo":{"desktop-webmail":{"2020-01":"n #1","2022-12":"n #6"},"ios":{"2020-01":"n #1","2022-12":"n"},"android":{"2020-01":"n #1","2022-12":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n","2022-12":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"}},"hey":{"desktop-webmail":{"2020-06":"y","2022-12":"n #5"}},"mail-ru":{"desktop-webmail":{"2020-10":"n","2022-12":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"n #2","2022-12":"y #4"}},"laposte":{"desktop-webmail":{"2021-08":"y","2022-12":"y"}},"free-fr":{"desktop-webmail":{"2022-12":"y"}},"t-online-de":{"desktop-webmail":{"2022-12":"n"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"10.3":"n","12.4":"y","16.0":"y"},"ios":{"12.2":"n","13.0":"y","16.1":"y"}},"gmail":{"desktop-webmail":{"2020-01":"n","2022-12":"n"},"ios":{"2020-01":"n","2022-12":"n"},"android":{"2020-01":"n","2022-12":"n"},"mobile-webmail":{"2020-02":"n","2022-12":"n"}},"orange":{"desktop-webmail":{"2019-08":"y","2021-03":"y","2022-12":"y","2024-04":"y"},"ios":{"2020-01":"n","2022-12":"y","2024-04":"y"},"android":{"2020-01":"n","2022-12":"n","2024-04":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-01":"n"},"macos":{"2019":"y","16.70":"y #3","16.80":"y #3"},"outlook-com":{"2019-07":"y","2022-12":"y #3"},"ios":{"2020-01":"y","2022-12":"y #3"},"android":{"2020-01":"n","2022-12":"n #3","2023-03":"y #3"}},"samsung-email":{"android":{"6.0":"n","6.1":"y"}},"sfr":{"desktop-webmail":{"2019-08":"y","2022-12":"y","2025-07":"n"},"ios":{"2019-08":"n","2022-12":"n"},"android":{"2019-08":"n","2022-12":"n"}},"thunderbird":{"macos":{"60.8":"n","68.4":"y","78.5":"n","91.13":"n"}},"aol":{"desktop-webmail":{"2020-01":"n #1"},"ios":{"2020-01":"n #1"},"android":{"2020-01":"n #1"}},"yahoo":{"desktop-webmail":{"2020-01":"n #1","2022-12":"n #6"},"ios":{"2020-01":"n #1","2022-12":"n"},"android":{"2020-01":"n #1","2022-12":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n","2022-12":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"}},"hey":{"desktop-webmail":{"2020-06":"y","2022-12":"n #5"}},"mail-ru":{"desktop-webmail":{"2020-10":"n","2022-12":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"n #2","2022-12":"y #4"}},"laposte":{"desktop-webmail":{"2021-08":"y","2022-12":"y","2025-07":"n"}},"free-fr":{"desktop-webmail":{"2022-12":"y"}},"t-online-de":{"desktop-webmail":{"2022-12":"n"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Not supported. `@media (prefers-color-scheme)` is transformed into `@media ( _filtered_a )`.","2":"Not supported. `@media (prefers-color-scheme:dark)` is transformed into `@media none`.","3":"Additional custom `data` attributes (`data-ogsc`, `data-ogac`, `data-ogsb`, `data-ogab`) are added when viewing an email in dark mode. See [this article](https://www.hteumeuleu.com/2021/emails-react-outlook-com-dark-mode/) for examples.","4":"`@media (prefers-color-scheme:dark)` is transformed into `@media all` at run time if it applies.","5":"Not supported. `@media (prefers-color-scheme:dark)` is transformed into `@media (false)`","6":"Not supported. `@media (prefers-color-scheme:dark)` is transformed into `@media ()`"}
},
@@ -222,9 +222,9 @@
"last_test_date":"2021-02-20",
"test_url":"https://www.caniemail.com/tests/css-media-prefers-reduced-motion.html",
"test_results_url":"https://testi.at/proj/e3GT3l1CxqBUoE3u9keC4WLf5",
"stats":{"apple-mail":{"macos":{"11":"y","12":"y","13":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y"}},"gmail":{"desktop-webmail":{"2020-12":"n"},"ios":{"2020-12":"n"},"android":{"2020-12":"n"},"mobile-webmail":{"2020-12":"n"}},"orange":{"desktop-webmail":{"2021-02":"y","2021-03":"y"},"ios":{"2021-02":"y"},"android":{"2021-02":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"16005.13426.20316.0":"n"},"macos":{"2020-12":"y","16.80":"y"},"outlook-com":{"2020-12":"y"},"ios":{"2020-12":"y"},"android":{"4.2048.4":"y"}},"yahoo":{"desktop-webmail":{"2020-12":"n"},"ios":{"2021-02":"n"},"android":{"6.16.2.1519779":"n"}},"aol":{"desktop-webmail":{"2020-12":"n"},"ios":{"2021-02":"n"},"android":{"2021-02":"n"}},"samsung-email":{"android":{"6.1.31.2":"y"}},"sfr":{"desktop-webmail":{"2021-02":"y"},"ios":{"2021-02":"n"},"android":{"2021-02":"n"}},"thunderbird":{"macos":{"78.7":"n"}},"protonmail":{"desktop-webmail":{"2021-02":"n"},"ios":{"2021-02":"n"},"android":{"2021-02":"n"}},"hey":{"desktop-webmail":{"2021-02":"y"}},"mail-ru":{"desktop-webmail":{"2021-02":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"n #1"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"11":"y","12":"y","13":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y"}},"gmail":{"desktop-webmail":{"2020-12":"n"},"ios":{"2020-12":"n"},"android":{"2020-12":"n"},"mobile-webmail":{"2020-12":"n"}},"orange":{"desktop-webmail":{"2021-02":"y","2021-03":"y"},"ios":{"2021-02":"y"},"android":{"2021-02":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"16005.13426.20316.0":"n"},"macos":{"2020-12":"y","16.80":"y"},"outlook-com":{"2020-12":"y"},"ios":{"2020-12":"y"},"android":{"4.2048.4":"y"}},"yahoo":{"desktop-webmail":{"2020-12":"n"},"ios":{"2021-02":"n"},"android":{"6.16.2.1519779":"n"}},"aol":{"desktop-webmail":{"2020-12":"n"},"ios":{"2021-02":"n"},"android":{"2021-02":"n"}},"samsung-email":{"android":{"6.1.31.2":"y"}},"sfr":{"desktop-webmail":{"2021-02":"y"},"ios":{"2021-02":"n"},"android":{"2021-02":"n"}},"thunderbird":{"macos":{"78.7":"n"}},"protonmail":{"desktop-webmail":{"2021-02":"a #2"},"ios":{"2021-02":"a #2"},"android":{"2021-02":"a #2"}},"hey":{"desktop-webmail":{"2021-02":"y"}},"mail-ru":{"desktop-webmail":{"2021-02":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"n #1"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Not supported. `@media (prefers-reduced-motion:reduce)` is transformed into `@media none`."}
"notes_by_num":{"1":"Not supported. `@media (prefers-reduced-motion:reduce)` is transformed into `@media none`.","2":"Partially supported. Not supported on `picture`."}
},
{
@@ -238,7 +238,7 @@
"last_test_date":"2023-12-13",
"test_url":"https://www.caniemail.com/tests/css-media.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/hMLCNCSKZYHkLgLOpIWltlnYjtagbNsrwzMxalc2VbghN/list",
"stats":{"apple-mail":{"macos":{"10.3":"y"},"ios":{"10.3":"y","12.2":"y"}},"gmail":{"desktop-webmail":{"2019-08":"a #1 #7","2020-01":"a #7"},"ios":{"2019-08":"a #1 #6 #7","2020-01":"a #6 #7"},"android":{"2019-08":"a #1 #6 #7","2022-07":"a #6 #7"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-08":"y #5","2021-03":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"outlook":{"windows":{"2003":"a #1","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-01":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1 #10"},"outlook-com":{"2019-08":"a #1","2023-12":"a #1 #10"},"ios":{"2019-08":"a #1"},"android":{"2019-08":"a #1"}},"samsung-email":{"android":{"5.0.10.2":"y","6.0":"y","6.1.90.16":"a #9"}},"sfr":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"n"},"android":{"2019-08":"n"}},"thunderbird":{"macos":{"60.3":"y","78.5":"n","102.11":"n"}},"yahoo":{"desktop-webmail":{"2019-08":"a #1 #2","2020-01":"a #2"},"ios":{"2019-08":"a #1 #2","2020-01":"a #2"},"android":{"2019-08":"a #1 #2 #3","2020-01":"a #2 #3"}},"aol":{"desktop-webmail":{"2019-02":"a #1 #2","2020-01":"a #2"},"ios":{"2019-02":"a #1 #2","2020-01":"a #2"},"android":{"2019-02":"a #1 #2","2020-01":"a #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n","2023-05":"a #8"},"ios":{"2020-03":"n","2023-05":"a #8"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"a #1 #7"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"y #1"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"y #1"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"10.3":"y"},"ios":{"10.3":"y","12.2":"y"}},"gmail":{"desktop-webmail":{"2019-08":"a #1 #7","2020-01":"a #7"},"ios":{"2019-08":"a #1 #6 #7","2020-01":"a #6 #7"},"android":{"2019-08":"a #1 #6 #7","2022-07":"a #6 #7"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-08":"y #5","2021-03":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"outlook":{"windows":{"2003":"a #1","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-01":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1 #10"},"outlook-com":{"2019-08":"a #1","2023-12":"a #1 #10"},"ios":{"2019-08":"a #1"},"android":{"2019-08":"a #1"}},"samsung-email":{"android":{"5.0.10.2":"y","6.0":"y","6.1.90.16":"a #9"}},"sfr":{"desktop-webmail":{"2019-08":"y","2025-07":"n"},"ios":{"2019-08":"n"},"android":{"2019-08":"n"}},"thunderbird":{"macos":{"60.3":"y","78.5":"n","102.11":"n"}},"yahoo":{"desktop-webmail":{"2019-08":"a #1 #2","2020-01":"a #2"},"ios":{"2019-08":"a #1 #2","2020-01":"a #2"},"android":{"2019-08":"a #1 #2 #3","2020-01":"a #2 #3","2025-06":"a #2"}},"aol":{"desktop-webmail":{"2019-02":"a #1 #2","2020-01":"a #2"},"ios":{"2019-02":"a #1 #2","2020-01":"a #2"},"android":{"2019-02":"a #1 #2","2020-01":"a #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n","2023-05":"a #8"},"ios":{"2020-03":"n","2023-05":"a #8"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"a #1 #7"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-06":"y #1"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"y #1"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Does not support nested media queries.","2":"Partial. Only supports `screen`, `min-width`, `max-width`, `min-height` and `max-height` based media queries.","3":"Buggy. Requires a double `<head>` hack to work.","4":"Partial. Does not support simple `@media {}` declarations.","5":"Buggy. The first rule inside a media query is not prefixed.","6":"Partial. Not supported with non Google accounts.","7":"Partial. Does not support height based media queries.","8":"Partial. Does not support landscape media query.","9":"Partial. Not supported with Hotmail/Outlook accounts.","10":"Partial. Nested media queries are removed."}
},
@@ -254,7 +254,7 @@
"last_test_date":"2020-05-25",
"test_url":"https://www.caniemail.com/tests/css-at-supports.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/No78GouZXTsxEZCD6z4Hn2frAvg3tHBw1SRAP8SwPKsZ5/list",
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"13":"y"}},"gmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"},"mobile-webmail":{"2020-05":"n"}},"orange":{"desktop-webmail":{"2020-05":"y","2021-03":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-05":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"thunderbird":{"macos":{"68.7":"y","78.5":"n"}},"aol":{"desktop-webmail":{"2020-05":"y #1"},"ios":{"2020-05":"y #1"},"android":{"2020-05":"y #1"}},"yahoo":{"desktop-webmail":{"2020-05":"y #1"},"ios":{"2020-05":"y #1"},"android":{"2020-05":"y #1"}},"protonmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"n #2"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"13":"y"}},"gmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"},"mobile-webmail":{"2020-05":"n"}},"orange":{"desktop-webmail":{"2020-05":"y","2021-03":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-05":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2020-05":"y","2025-07":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"thunderbird":{"macos":{"68.7":"y","78.5":"n"}},"aol":{"desktop-webmail":{"2020-05":"y #1"},"ios":{"2020-05":"y #1"},"android":{"2020-05":"y #1"}},"yahoo":{"desktop-webmail":{"2020-05":"y #1"},"ios":{"2020-05":"y #1"},"android":{"2020-05":"y #1"}},"protonmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"n #2"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Properties not supported by the client are replaced by `_filtered_a` inside the parenthesis.","2":"Not supported. `@supports` is transformed into `@media not all`."}
},
@@ -270,7 +270,7 @@
"last_test_date":"2024-01-17",
"test_url":"https://www.caniemail.com/tests/css-backdrop-filter.html",
"test_results_url":"https://testi.at/proj/p4r7t9n30o7nh7vvfpn",
"stats":{"apple-mail":{"macos":{"10":"y #1","11":"u","12":"u","13":"y #1"},"ios":{"11":"n","12":"n","13":"y #1","14":"y #1","15":"y #1"}},"gmail":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"},"mobile-webmail":{"2024-01":"n"}},"orange":{"desktop-webmail":{"2024-01":"u"},"ios":{"2024-01":"n"},"android":{"2024-01":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-01":"n"},"macos":{"2024-01":"y"},"outlook-com":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"}},"yahoo":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"}},"aol":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"}},"samsung-email":{"android":{"2024-01":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"2024-01":"u"}},"protonmail":{"desktop-webmail":{"2024-01":"u"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"hey":{"desktop-webmail":{"2024-01":"u"}},"mail-ru":{"desktop-webmail":{"2024-01":"y"}},"fastmail":{"desktop-webmail":{"2024-01":"u"}},"laposte":{"desktop-webmail":{"2024-01":"u"}},"gmx":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"web-de":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-01":"u"},"android":{"2024-01":"u"}}},
"stats":{"apple-mail":{"macos":{"10":"y #1","11":"u","12":"u","13":"y #1"},"ios":{"11":"n","12":"n","13":"y #1","14":"y #1","15":"y #1"}},"gmail":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"},"mobile-webmail":{"2024-01":"n"}},"orange":{"desktop-webmail":{"2024-01":"u"},"ios":{"2024-01":"n"},"android":{"2024-01":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-01":"n"},"macos":{"2024-01":"y"},"outlook-com":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"}},"yahoo":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"}},"aol":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"}},"samsung-email":{"android":{"2024-01":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"2024-01":"u"}},"protonmail":{"desktop-webmail":{"2024-01":"y"},"ios":{"2024-01":"y"},"android":{"2024-01":"y"}},"hey":{"desktop-webmail":{"2024-01":"u"}},"mail-ru":{"desktop-webmail":{"2024-01":"y"}},"fastmail":{"desktop-webmail":{"2024-01":"u"}},"laposte":{"desktop-webmail":{"2024-01":"u"}},"gmx":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"web-de":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-01":"u"},"android":{"2024-01":"u"}}},
"notes":null,
"notes_by_num":{"1":"Works with prefix `-webkit`"}
},
@@ -430,7 +430,7 @@
"last_test_date":"2022-07-14",
"test_url":"https://www.caniemail.com/tests/css-block-size.html",
"test_results_url":"https://testi.at/proj/0xeT11rcnx6IzN7f9NsVFlZ",
"stats":{"apple-mail":{"macos":{"10.13":"n","10.15":"y","11":"y","12":"y"},"ios":{"14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2022":"n"},"windows-mail":{"2022-07":"n"},"macos":{"16.56":"y","16.80":"n"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"91.11.0":"y"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"y"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"y"}},"laposte":{"desktop-webmail":{"2022-07":"y"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"stats":{"apple-mail":{"macos":{"10.13":"n","10.15":"y","11":"y","12":"y"},"ios":{"14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2022":"n"},"windows-mail":{"2022-07":"n"},"macos":{"16.56":"y","16.80":"n"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"91.11.0":"y"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"y"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"y"}},"laposte":{"desktop-webmail":{"2022-07":"y"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -446,7 +446,7 @@
"last_test_date":"2023-12-20",
"test_url":"https://www.caniemail.com/tests/css-border-collapse.html",
"test_results_url":"https://testi.at/proj/4zk4fe7tv86fn4bc6",
"stats":{"apple-mail":{"macos":{"2023-12":"y"},"ios":{"2023-12":"y"}},"gmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"},"mobile-webmail":{"2023-12":"y"}},"orange":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"outlook":{"windows":{"2023-12":"y"},"windows-mail":{"2023-12":"y"},"macos":{"2023-12":"y"},"outlook-com":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"yahoo":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"aol":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"samsung-email":{"android":{"2023-12":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"2023-12":"y"}},"protonmail":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"hey":{"desktop-webmail":{"2023-12":"u"}},"mail-ru":{"desktop-webmail":{"2023-12":"y"}},"fastmail":{"desktop-webmail":{"2023-12":"u"}},"laposte":{"desktop-webmail":{"2023-12":"u"}},"gmx":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"web-de":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2023-12":"u"},"android":{"2023-12":"u"}}},
"stats":{"apple-mail":{"macos":{"2023-12":"y"},"ios":{"2023-12":"y"}},"gmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"},"mobile-webmail":{"2023-12":"y"}},"orange":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"outlook":{"windows":{"2023-12":"y"},"windows-mail":{"2023-12":"y"},"macos":{"2023-12":"y"},"outlook-com":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"yahoo":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"aol":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"samsung-email":{"android":{"2023-12":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"2023-12":"y"}},"protonmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"hey":{"desktop-webmail":{"2023-12":"u"}},"mail-ru":{"desktop-webmail":{"2023-12":"y"}},"fastmail":{"desktop-webmail":{"2023-12":"u"}},"laposte":{"desktop-webmail":{"2023-12":"u"}},"gmx":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"web-de":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2023-12":"u"},"android":{"2023-12":"u"}}},
"notes":null,
"notes_by_num":null
},
@@ -478,7 +478,7 @@
"last_test_date":"2022-07-14",
"test_url":"https://www.caniemail.com/tests/css-border-logical-properties.html",
"test_results_url":"https://testi.at/proj/1yxFDAGtwrUmbf4tzMTY",
"stats":{"apple-mail":{"macos":{"10.12":"n","10.13":"n","10.15":"a #1","11":"y","12":"y"},"ios":{"11":"n","12":"a #1","13":"a #1","14":"a #1","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"a #1","2016":"a #1","16.80":"n"},"outlook-com":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"a #1","11":"a #1"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"stats":{"apple-mail":{"macos":{"10.12":"n","10.13":"n","10.15":"a #1","11":"y","12":"y"},"ios":{"11":"n","12":"a #1","13":"a #1","14":"a #1","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"a #1","2016":"a #1","16.80":"n"},"outlook-com":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"a #1","11":"a #1"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. `border-<inline/block>-color` and `border-<inline/block>-width` does not work."}
},
@@ -494,7 +494,7 @@
"last_test_date":"2022-07-14",
"test_url":"https://www.caniemail.com/tests/css-border-logical-properties.html",
"test_results_url":"https://testi.at/proj/1yxFDAGtwrUmbf4tzMTY",
"stats":{"apple-mail":{"macos":{"10.12":"n","10.13":"n","10.15":"y","11":"y","12":"y"},"ios":{"11":"n","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"stats":{"apple-mail":{"macos":{"10.12":"n","10.13":"n","10.15":"y","11":"y","12":"y"},"ios":{"11":"n","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -510,7 +510,7 @@
"last_test_date":"2022-07-13",
"test_url":"https://www.caniemail.com/tests/css-border-logical-properties.html",
"test_results_url":"https://testi.at/proj/1yxFDAGtwrUmbf4tzMTY",
"stats":{"apple-mail":{"macos":{"10.15":"n","11":"y","12":"y"},"ios":{"13":"n","14":"n","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"n","2016":"n","16.80":"n"},"outlook-com":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"n","11":"n"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"stats":{"apple-mail":{"macos":{"10.15":"n","11":"y","12":"y"},"ios":{"13":"n","14":"n","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"n","2016":"n","16.80":"n"},"outlook-com":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"n","11":"n"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -526,7 +526,7 @@
"last_test_date":"2022-08-16",
"test_url":"https://www.caniemail.com/tests/css-border-logical-properties.html",
"test_results_url":"https://testi.at/proj/1yxFDAGtwrUmbf4tzMTY",
"stats":{"apple-mail":{"macos":{"10.15":"n","11":"n","12":"y"},"ios":{"13":"n","14":"n","15":"y"}},"gmail":{"desktop-webmail":{"2022-08":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"},"mobile-webmail":{"2022-08":"n"}},"orange":{"desktop-webmail":{"2022-08":"u"},"ios":{"2022-08":"u"},"android":{"2022-08":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-08":"n"},"macos":{"2011":"n","2016":"n","16.80":"n"},"outlook-com":{"2022-08":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"}},"samsung-email":{"android":{"10":"n","11":"n"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-08":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"}},"yahoo":{"desktop-webmail":{"2022-08":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"}},"protonmail":{"desktop-webmail":{"2022-08":"u"},"ios":{"2022-08":"u"},"android":{"2022-08":"u"}},"hey":{"desktop-webmail":{"2022-08":"u"}},"mail-ru":{"desktop-webmail":{"2022-08":"y"}},"fastmail":{"desktop-webmail":{"2022-08":"u"}},"laposte":{"desktop-webmail":{"2022-08":"u"}}},
"stats":{"apple-mail":{"macos":{"10.15":"n","11":"n","12":"y"},"ios":{"13":"n","14":"n","15":"y"}},"gmail":{"desktop-webmail":{"2022-08":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"},"mobile-webmail":{"2022-08":"n"}},"orange":{"desktop-webmail":{"2022-08":"u"},"ios":{"2022-08":"u"},"android":{"2022-08":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-08":"n"},"macos":{"2011":"n","2016":"n","16.80":"n"},"outlook-com":{"2022-08":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"}},"samsung-email":{"android":{"10":"n","11":"n"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-08":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"}},"yahoo":{"desktop-webmail":{"2022-08":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"}},"protonmail":{"desktop-webmail":{"2022-08":"y"},"ios":{"2022-08":"y"},"android":{"2022-08":"y"}},"hey":{"desktop-webmail":{"2022-08":"u"}},"mail-ru":{"desktop-webmail":{"2022-08":"y"}},"fastmail":{"desktop-webmail":{"2022-08":"u"}},"laposte":{"desktop-webmail":{"2022-08":"u"}}},
"notes":null,
"notes_by_num":null
},
@@ -558,7 +558,7 @@
"last_test_date":"2023-12-20",
"test_url":"https://www.caniemail.com/tests/css-border-spacing.html",
"test_results_url":"https://testi.at/proj/dyodfk8c5dhjanflz",
"stats":{"apple-mail":{"macos":{"2023-12":"y"},"ios":{"2023-12":"y"}},"gmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"},"mobile-webmail":{"2023-12":"y"}},"orange":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2023-12":"n"},"macos":{"2023-12":"n"},"outlook-com":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"yahoo":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"aol":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"samsung-email":{"android":{"2023-12":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"2023-12":"y"}},"protonmail":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"hey":{"desktop-webmail":{"2023-12":"u"}},"mail-ru":{"desktop-webmail":{"2023-12":"y"}},"fastmail":{"desktop-webmail":{"2023-12":"u"}},"laposte":{"desktop-webmail":{"2023-12":"u"}},"gmx":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"web-de":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2023-12":"u"},"android":{"2023-12":"u"}}},
"stats":{"apple-mail":{"macos":{"2023-12":"y"},"ios":{"2023-12":"y"}},"gmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"},"mobile-webmail":{"2023-12":"y"}},"orange":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2023-12":"n"},"macos":{"2023-12":"n"},"outlook-com":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"yahoo":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"aol":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"samsung-email":{"android":{"2023-12":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"2023-12":"y"}},"protonmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"hey":{"desktop-webmail":{"2023-12":"u"}},"mail-ru":{"desktop-webmail":{"2023-12":"y"}},"fastmail":{"desktop-webmail":{"2023-12":"u"}},"laposte":{"desktop-webmail":{"2023-12":"u"}},"gmx":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"web-de":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2023-12":"u"},"android":{"2023-12":"u"}}},
"notes":null,
"notes_by_num":null
},
@@ -665,7 +665,7 @@
"description":"Changes the default colors of HTML elements. Useful for when you want an email to display only in a dark color scheme or only a light scheme, regardless of user settings",
"url":"https://www.caniemail.com/features/css-color-scheme/",
"category":"css",
"tags":[],
"tags":["accessibility"],
"keywords":"dark mode, light mode",
"last_test_date":"2023-09-18",
"test_url":"https://www.caniemail.com/tests/css-color-scheme.html",
@@ -739,6 +739,22 @@
"notes_by_num":{"1":"Partial. Not supported with Hotmail/Outlook accounts."}
},
{
"slug":"css-cursor",
"title":"cursor",
"description":"The cursor CSS property sets the mouse cursor, if any, to show when the mouse pointer is over an element.",
"url":"https://www.caniemail.com/features/css-cursor/",
"category":"css",
"tags":["accessibility"],
"keywords":"pointer, mouse, touch",
"last_test_date":"2025-07-02",
"test_url":"https://www.caniemail.com/tests/css-cursor.html",
"test_results_url":"https://testi.at/proj/52gbh94rh6lncdl4fge",
"stats":{"apple-mail":{"macos":{"15":"a #1"},"ios":{"15":"n #3"}},"gmail":{"desktop-webmail":{"2025-07":"n #2"},"ios":{"2025-07":"n #2"},"android":{"2025-07":"n #2"},"mobile-webmail":{"2025-07":"n #2"}},"orange":{"desktop-webmail":{"2025-07":"u"},"ios":{"2025-07":"u"},"android":{"2025-07":"u"}},"outlook":{"windows":{"2007":"u","2010":"u","2013":"u","2016":"u","2019":"u"},"windows-mail":{"2025-07":"u"},"macos":{"16.98":"n"},"outlook-com":{"2025-07":"n"},"ios":{"2025-07":"n #3"},"android":{"2025-07":"n"}},"samsung-email":{"android":{"6.0":"u"}},"sfr":{"desktop-webmail":{"2025-07":"u"},"ios":{"2025-07":"u"},"android":{"2025-07":"u"}},"thunderbird":{"macos":{"78.14":"y"}},"aol":{"desktop-webmail":{"2025-07":"u"},"ios":{"2025-07":"u"},"android":{"2025-07":"u"}},"yahoo":{"desktop-webmail":{"2025-07":"a #4"},"ios":{"2025-07":"n #3"},"android":{"2025-07":"a #4"}},"protonmail":{"desktop-webmail":{"2025-07":"a #5"},"ios":{"2025-07":"u"},"android":{"2025-07":"u"}},"hey":{"desktop-webmail":{"2025-07":"u"}},"mail-ru":{"desktop-webmail":{"2025-07":"u"}},"fastmail":{"desktop-webmail":{"2025-07":"u"}},"laposte":{"desktop-webmail":{"2025-07":"u"}},"free-fr":{"desktop-webmail":{"2025-07":"u"}},"t-online-de":{"desktop-webmail":{"2025-07":"u"}},"gmx":{"desktop-webmail":{"2025-07":"a #6"},"ios":{"2025-07":"n #3"},"android":{"2025-07":"y"}},"web-de":{"desktop-webmail":{"2025-07":"u"},"ios":{"2025-07":"u"},"android":{"2025-07":"u"}},"ionos-1and1":{"desktop-webmail":{"2025-07":"u"},"android":{"2025-07":"u"}}},
"notes":"Cursor appearance on Android mobile devices depends on external pointer device/mouse. Cursor on iOS mobile devices also requires assistive touch to be enabled, and does not appear to respond to content.",
"notes_by_num":{"1":"Partial. URL is not supported.","2":"Cursor property is removed.","3":"iOS assistive touch does not respond to cursor.","4":"Partial. Only supports: crosshair, help, move, pointer, progress, text, wait, auto, default, and all single-direction resize properties.","5":"Partial. URL buggy and only works inline.","6":"Partial. Inline CSS only. Only supports: crosshair, help, move, pointer, wait, auto, default, and all single-direction resize properties."}
},
{
"slug":"css-direction",
"title":"direction",
@@ -830,7 +846,7 @@
"last_test_date":"2024-08-23",
"test_url":"https://www.caniemail.com/tests/css-empty-cells.html",
"test_results_url":"https://testi.at/proj/kgl7t57xs8jxueze0v8",
"stats":{"apple-mail":{"macos":{"2024-08":"y"},"ios":{"2024-08":"y"}},"gmail":{"desktop-webmail":{"2024-08":"y"},"ios":{"2024-08":"y"},"android":{"2024-08":"y"},"mobile-webmail":{"2024-08":"u"}},"orange":{"desktop-webmail":{"2024-08":"u"},"ios":{"2024-08":"u"},"android":{"2024-08":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-08":"n"},"macos":{"2024-08":"y"},"outlook-com":{"2024-08":"y"},"ios":{"2024-08":"y"},"android":{"2024-08":"y"}},"yahoo":{"desktop-webmail":{"2024-08":"y"},"ios":{"2024-08":"n"},"android":{"2024-08":"n"}},"aol":{"desktop-webmail":{"2024-08":"y"},"ios":{"2024-08":"n"},"android":{"2024-08":"n"}},"samsung-email":{"android":{"2024-08":"y"}},"sfr":{"desktop-webmail":{"2024-03":"u"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"protonmail":{"desktop-webmail":{"2024-08":"u"},"ios":{"2024-08":"u"},"android":{"2024-08":"u"}},"hey":{"desktop-webmail":{"2024-08":"u"}},"mail-ru":{"desktop-webmail":{"2024-08":"n"}},"fastmail":{"desktop-webmail":{"2024-08":"u"}}},
"stats":{"apple-mail":{"macos":{"2024-08":"y"},"ios":{"2024-08":"y"}},"gmail":{"desktop-webmail":{"2024-08":"y"},"ios":{"2024-08":"y"},"android":{"2024-08":"y"},"mobile-webmail":{"2024-08":"u"}},"orange":{"desktop-webmail":{"2024-08":"u"},"ios":{"2024-08":"u"},"android":{"2024-08":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-08":"n"},"macos":{"2024-08":"y"},"outlook-com":{"2024-08":"y"},"ios":{"2024-08":"y"},"android":{"2024-08":"y"}},"yahoo":{"desktop-webmail":{"2024-08":"y"},"ios":{"2024-08":"n"},"android":{"2024-08":"n"}},"aol":{"desktop-webmail":{"2024-08":"y"},"ios":{"2024-08":"n"},"android":{"2024-08":"n"}},"samsung-email":{"android":{"2024-08":"y"}},"sfr":{"desktop-webmail":{"2024-03":"u"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"protonmail":{"desktop-webmail":{"2024-08":"y"},"ios":{"2024-08":"y"},"android":{"2024-08":"y"}},"hey":{"desktop-webmail":{"2024-08":"u"}},"mail-ru":{"desktop-webmail":{"2024-08":"n"}},"fastmail":{"desktop-webmail":{"2024-08":"u"}}},
"notes":null,
"notes_by_num":null
},
@@ -910,7 +926,7 @@
"last_test_date":"2022-08-01",
"test_url":"https://www.caniemail.com/tests/css-font-kerning.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/RlRYNGDjVNBhofxCNxloUcRbUVWGDhJ2kZ4fy6HXpEatH/list",
"stats":{"apple-mail":{"macos":{"11":"y","12":"y","13":"y","14":"y","15":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-08":"y"},"ios":{"2022-08":"y"},"android":{"2022-08":"y"},"mobile-webmail":{"2022-08":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"macos":{"2022-08":"y","16.80":"y"},"outlook-com":{"2022-08":"y"},"ios":{"2022-08":"y"},"android":{"4.2101.1":"y"}},"yahoo":{"desktop-webmail":{"2022-08":"n","2024-03":"n"},"ios":{"2024-03":"n"},"android":{"2024-03":"n"}},"aol":{"desktop-webmail":{"2022-08":"n"}},"samsung-email":{"android":{"6.1.31.2":"y"}},"mail-ru":{"desktop-webmail":{"2022-08":"n"}},"free-fr":{"desktop-webmail":{"2022-08":"y"}},"gmx":{"desktop-webmail":{"2022-08":"n"}},"t-online-de":{"desktop-webmail":{"2022-08":"n"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"thunderbird":{"macos":{"128.9.0":"y"}}},
"stats":{"apple-mail":{"macos":{"11":"y","12":"y","13":"y","14":"y","15":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-08":"y"},"ios":{"2022-08":"y"},"android":{"2022-08":"y"},"mobile-webmail":{"2022-08":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"macos":{"2022-08":"y","16.80":"y"},"outlook-com":{"2022-08":"y"},"ios":{"2022-08":"y"},"android":{"4.2101.1":"y"}},"yahoo":{"desktop-webmail":{"2022-08":"n","2024-03":"n"},"ios":{"2024-03":"n"},"android":{"2024-03":"n"}},"aol":{"desktop-webmail":{"2022-08":"n"}},"samsung-email":{"android":{"6.1.31.2":"y"}},"mail-ru":{"desktop-webmail":{"2022-08":"n"}},"free-fr":{"desktop-webmail":{"2022-08":"y"}},"gmx":{"desktop-webmail":{"2022-08":"n"}},"t-online-de":{"desktop-webmail":{"2022-08":"n"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"thunderbird":{"macos":{"128.9.0":"y"}},"protonmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -990,9 +1006,9 @@
"last_test_date":"2021-05-07",
"test_url":"https://www.caniemail.com/tests/css-clamp.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/zSEJIfc49LeYUVU5ncqsWBDRRTZlqq01sYRUSICWOs74Y/list",
"stats":{"apple-mail":{"macos":{"13":"n","14.0":"y"},"ios":{"13":"n","14.5":"y"}},"gmail":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"a #1"},"android":{"2021-05":"a #1"},"mobile-webmail":{"2021-05":"y"}},"orange":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2021-05":"n"},"macos":{"2011":"n","2016":"n","16.80":"n"},"outlook-com":{"2021-05":"n","2023-12":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"samsung-email":{"android":{"6.0":"n"}},"sfr":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"y"},"android":{"2021-05":"y"}},"thunderbird":{"macos":{"78.10":"y"}},"aol":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"yahoo":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"protonmail":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"y"},"android":{"2021-05":"y"}},"hey":{"desktop-webmail":{"2021-05":"y"}},"mail-ru":{"desktop-webmail":{"2021-05":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"n"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"13":"n","14.0":"y"},"ios":{"13":"n","14.5":"y"}},"gmail":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"a #1"},"android":{"2021-05":"a #1"},"mobile-webmail":{"2021-05":"y"}},"orange":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2021-05":"n"},"macos":{"2011":"n","2016":"n","16.80":"n"},"outlook-com":{"2021-05":"n","2023-12":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"samsung-email":{"android":{"6.0":"n","6.2.06.0":"a #2"}},"sfr":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"y"},"android":{"2021-05":"y"}},"thunderbird":{"macos":{"78.10":"y"}},"aol":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"yahoo":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"protonmail":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"y"},"android":{"2021-05":"y"}},"hey":{"desktop-webmail":{"2021-05":"y"}},"mail-ru":{"desktop-webmail":{"2021-05":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"n"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Not supported with non Google accounts."}
"notes_by_num":{"1":"Partial. Not supported with non Google accounts.","2":"Partial. Not supported with Microsoft accounts."}
},
{
@@ -1001,14 +1017,14 @@
"description":"Enables setting two colors (one for light and the other for dark mode) for a property.",
"url":"https://www.caniemail.com/features/css-function-light-dark/",
"category":"css",
"tags":[],
"tags":["accessibility"],
"keywords":"dark, light",
"last_test_date":"2024-08-14",
"test_url":"https://www.caniemail.com/tests/css-function-light-dark.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/Lai13xyIE95H6jo1BBs6ay0f3RvJdPL344S3j3M7FbeU4/list",
"stats":{"apple-mail":{"macos":{"16.0":"y #1"},"ios":{"17.5.1":"y"}},"gmail":{"desktop-webmail":{"2024-08":"n"},"ios":{"2024-08":"n"},"android":{"2024-08":"n"},"mobile-webmail":{"2024-08":"n"}},"orange":{"desktop-webmail":{"2024-08":"n"},"ios":{"2024-08":"n"},"android":{"2024-08":"u"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2024-08":"n"},"macos":{"16.88":"n"},"outlook-com":{"2024-08":"n"},"ios":{"2024-08":"n"},"android":{"2024-08":"u"}},"samsung-email":{"android":{"6.0":"u"}},"sfr":{"desktop-webmail":{"2024-08":"a #2"},"ios":{"2024-08":"a #1 #2"},"android":{"2024-08":"u"}},"thunderbird":{"macos":{"115.10.1":"n","128.1.0":"y"}},"aol":{"desktop-webmail":{"2024-08":"n"},"ios":{"2024-08":"n"},"android":{"2024-08":"u"}},"yahoo":{"desktop-webmail":{"2024-08":"n"},"ios":{"2024-08":"n"},"android":{"2024-08":"u"}},"protonmail":{"desktop-webmail":{"2024-08":"a #2"},"ios":{"2024-08":"y #1"},"android":{"2024-08":"u"}},"hey":{"desktop-webmail":{"2024-08":"a #2"}},"mail-ru":{"desktop-webmail":{"2024-08":"a #2"}},"fastmail":{"desktop-webmail":{"2024-08":"u"}},"laposte":{"desktop-webmail":{"2024-08":"a #2"}},"free-fr":{"desktop-webmail":{"2024-08":"n"}},"t-online-de":{"desktop-webmail":{"2024-08":"a #2"}},"gmx":{"desktop-webmail":{"2024-08":"n"}}},
"stats":{"apple-mail":{"macos":{"16.0":"y #1"},"ios":{"17.5.1":"y"}},"gmail":{"desktop-webmail":{"2024-08":"n"},"ios":{"2024-08":"n"},"android":{"2024-08":"n"},"mobile-webmail":{"2024-08":"n"}},"orange":{"desktop-webmail":{"2024-08":"n"},"ios":{"2024-08":"n"},"android":{"2024-08":"u"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2024-08":"n"},"macos":{"16.88":"n"},"outlook-com":{"2024-08":"n"},"ios":{"2024-08":"n"},"android":{"2024-08":"u"}},"samsung-email":{"android":{"6.2":"a #3"}},"sfr":{"desktop-webmail":{"2024-08":"a #2"},"ios":{"2024-08":"a #1 #2"},"android":{"2024-08":"u"}},"thunderbird":{"macos":{"115.10.1":"n","128.1.0":"y"}},"aol":{"desktop-webmail":{"2024-08":"n"},"ios":{"2024-08":"n"},"android":{"2024-08":"u"}},"yahoo":{"desktop-webmail":{"2024-08":"n"},"ios":{"2024-08":"n"},"android":{"2024-08":"u"}},"protonmail":{"desktop-webmail":{"2024-08":"a #2"},"ios":{"2024-08":"y #1"},"android":{"2024-08":"u"}},"hey":{"desktop-webmail":{"2024-08":"a #2"}},"mail-ru":{"desktop-webmail":{"2024-08":"a #2"}},"fastmail":{"desktop-webmail":{"2024-08":"u"}},"laposte":{"desktop-webmail":{"2024-08":"a #2"}},"free-fr":{"desktop-webmail":{"2024-08":"n"}},"t-online-de":{"desktop-webmail":{"2024-08":"a #2"}},"gmx":{"desktop-webmail":{"2024-08":"n"}}},
"notes":null,
"notes_by_num":{"1":"Only supported if youve updated your OS with Safari 17.5 or later.","2":"Buggy. The function is supported but the color stays light even in dark mode."}
"notes_by_num":{"1":"Only supported if youve updated your OS with Safari 17.5 or later.","2":"Buggy. The function is supported but the color stays light even in dark mode.","3":"Partial. Not supported with Hotmail/Outlook accounts."}
},
{
@@ -1022,9 +1038,9 @@
"last_test_date":"2021-05-07",
"test_url":"https://www.caniemail.com/tests/css-clamp.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/zSEJIfc49LeYUVU5ncqsWBDRRTZlqq01sYRUSICWOs74Y/list",
"stats":{"apple-mail":{"macos":{"13":"y","14.0":"y"},"ios":{"13":"y","14.5":"y"}},"gmail":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"a #1"},"android":{"2021-05":"a #1"},"mobile-webmail":{"2021-05":"y"}},"orange":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2021-05":"n"},"macos":{"2011":"n","2016":"y","16.80":"n"},"outlook-com":{"2021-05":"n","2023-12":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"samsung-email":{"android":{"6.0":"n"}},"sfr":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"y"},"android":{"2021-05":"y"}},"thunderbird":{"macos":{"78.10":"y"}},"aol":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"yahoo":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"protonmail":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"y"},"android":{"2021-05":"y"}},"hey":{"desktop-webmail":{"2021-05":"y"}},"mail-ru":{"desktop-webmail":{"2021-05":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"n"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"13":"y","14.0":"y"},"ios":{"13":"y","14.5":"y"}},"gmail":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"a #1"},"android":{"2021-05":"a #1"},"mobile-webmail":{"2021-05":"y"}},"orange":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2021-05":"n"},"macos":{"2011":"n","2016":"y","16.80":"n"},"outlook-com":{"2021-05":"n","2023-12":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"samsung-email":{"android":{"6.0":"n","6.2.06.0":"a #2"}},"sfr":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"y"},"android":{"2021-05":"y"}},"thunderbird":{"macos":{"78.10":"y"}},"aol":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"yahoo":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"protonmail":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"y"},"android":{"2021-05":"y"}},"hey":{"desktop-webmail":{"2021-05":"y"}},"mail-ru":{"desktop-webmail":{"2021-05":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"n"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Not supported with non Google accounts."}
"notes_by_num":{"1":"Partial. Not supported with non Google accounts.","2":"Partial. Not supported with Microsoft accounts."}
},
{
@@ -1038,9 +1054,9 @@
"last_test_date":"2021-05-07",
"test_url":"https://www.caniemail.com/tests/css-clamp.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/zSEJIfc49LeYUVU5ncqsWBDRRTZlqq01sYRUSICWOs74Y/list",
"stats":{"apple-mail":{"macos":{"13":"y","14.0":"y"},"ios":{"13":"y","14.5":"y"}},"gmail":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"a #1"},"android":{"2021-05":"a #1"},"mobile-webmail":{"2021-05":"y"}},"orange":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2021-05":"n"},"macos":{"2011":"n","2016":"y","16.80":"n"},"outlook-com":{"2021-05":"n","2023-12":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"samsung-email":{"android":{"6.0":"n"}},"sfr":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"y"},"android":{"2021-05":"y"}},"thunderbird":{"macos":{"78.10":"y"}},"aol":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"yahoo":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"protonmail":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"y"},"android":{"2021-05":"y"}},"hey":{"desktop-webmail":{"2021-05":"y"}},"mail-ru":{"desktop-webmail":{"2021-05":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"n"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"13":"y","14.0":"y"},"ios":{"13":"y","14.5":"y"}},"gmail":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"a #1"},"android":{"2021-05":"a #1"},"mobile-webmail":{"2021-05":"y"}},"orange":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2021-05":"n"},"macos":{"2011":"n","2016":"y","16.80":"n"},"outlook-com":{"2021-05":"n","2023-12":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"samsung-email":{"android":{"6.0":"n","6.2.06.0":"a #2"}},"sfr":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"y"},"android":{"2021-05":"y"}},"thunderbird":{"macos":{"78.10":"y"}},"aol":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"yahoo":{"desktop-webmail":{"2021-05":"n"},"ios":{"2021-05":"n"},"android":{"2021-05":"n"}},"protonmail":{"desktop-webmail":{"2021-05":"y"},"ios":{"2021-05":"y"},"android":{"2021-05":"y"}},"hey":{"desktop-webmail":{"2021-05":"y"}},"mail-ru":{"desktop-webmail":{"2021-05":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"n"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Not supported with non Google accounts."}
"notes_by_num":{"1":"Partial. Not supported with non Google accounts.","2":"Partial. Not supported with Microsoft accounts."}
},
{
@@ -1102,7 +1118,7 @@
"last_test_date":"2024-06-19",
"test_url":"https://www.caniemail.com/tests/css-hyphenate-character.html",
"test_results_url":"https://testi.at/proj/vr3e1e5bikda08oxc2",
"stats":{"apple-mail":{"macos":{"20":"n","21":"n","22":"n","23":"y"},"ios":{"11":"n","12":"n","13":"n","14":"n","15":"y"}},"gmail":{"desktop-webmail":{"2024-06":"n"},"ios":{"2024-06":"n"},"android":{"2024-06":"n"},"mobile-webmail":{"2024-06":"n"}},"orange":{"desktop-webmail":{"2024-06":"u"},"ios":{"2024-06":"u"},"android":{"2024-06":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-06":"n"},"macos":{"2024-06":"n"},"outlook-com":{"2024-06":"n"},"ios":{"2024-06":"n"},"android":{"2024-06":"n"}},"yahoo":{"desktop-webmail":{"2024-06":"n"},"ios":{"2024-06":"n"},"android":{"2024-06":"n"}},"aol":{"desktop-webmail":{"2024-06":"n"},"ios":{"2024-06":"n"},"android":{"2024-06":"n"}},"samsung-email":{"android":{"2024-06":"y"}},"sfr":{"desktop-webmail":{"2024-03":"u"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"protonmail":{"desktop-webmail":{"2024-06":"u"},"ios":{"2024-06":"u"},"android":{"2024-06":"u"}},"hey":{"desktop-webmail":{"2024-06":"u"}},"mail-ru":{"desktop-webmail":{"2024-06":"a #1"}},"fastmail":{"desktop-webmail":{"2024-06":"u"}},"laposte":{"desktop-webmail":{"2024-06":"u"}},"gmx":{"desktop-webmail":{"2024-06":"n"},"ios":{"2024-06":"u"},"android":{"2024-06":"u"}},"web-de":{"desktop-webmail":{"2024-06":"n"},"ios":{"2024-06":"u"},"android":{"2024-06":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-06":"u"},"android":{"2024-06":"u"}}},
"stats":{"apple-mail":{"macos":{"20":"n","21":"n","22":"n","23":"y"},"ios":{"11":"n","12":"n","13":"n","14":"n","15":"y"}},"gmail":{"desktop-webmail":{"2024-06":"n"},"ios":{"2024-06":"n"},"android":{"2024-06":"n"},"mobile-webmail":{"2024-06":"n"}},"orange":{"desktop-webmail":{"2024-06":"u"},"ios":{"2024-06":"u"},"android":{"2024-06":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-06":"n"},"macos":{"2024-06":"n"},"outlook-com":{"2024-06":"n"},"ios":{"2024-06":"n"},"android":{"2024-06":"n"}},"yahoo":{"desktop-webmail":{"2024-06":"n"},"ios":{"2024-06":"n"},"android":{"2024-06":"n"}},"aol":{"desktop-webmail":{"2024-06":"n"},"ios":{"2024-06":"n"},"android":{"2024-06":"n"}},"samsung-email":{"android":{"2024-06":"y"}},"sfr":{"desktop-webmail":{"2024-03":"u"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"protonmail":{"desktop-webmail":{"2024-06":"y"},"ios":{"2024-06":"y"},"android":{"2024-06":"y"}},"hey":{"desktop-webmail":{"2024-06":"u"}},"mail-ru":{"desktop-webmail":{"2024-06":"a #1"}},"fastmail":{"desktop-webmail":{"2024-06":"u"}},"laposte":{"desktop-webmail":{"2024-06":"u"}},"gmx":{"desktop-webmail":{"2024-06":"n"},"ios":{"2024-06":"u"},"android":{"2024-06":"u"}},"web-de":{"desktop-webmail":{"2024-06":"n"},"ios":{"2024-06":"u"},"android":{"2024-06":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-06":"u"},"android":{"2024-06":"u"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Does not support encoded character values"}
},
@@ -1150,9 +1166,9 @@
"last_test_date":"2021-11-30",
"test_url":"https://www.caniemail.com/tests/css-important.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/JEyxyPfKHFZCPKxlgiOugpH4lyNrXX39cd9M8xaW1DojH/list",
"stats":{"apple-mail":{"macos":{"13":"y","15":"y"},"ios":{"15":"y"}},"gmail":{"desktop-webmail":{"2021-11":"a #1"},"ios":{"2021-11":"a #1 #2"},"android":{"2021-11":"a #1 #2"},"mobile-webmail":{"2021-11":"a #1 #2"}},"orange":{"desktop-webmail":{"2021-11":"n #3"},"ios":{"2021-11":"n #3"},"android":{"2021-11":"n #3"}},"outlook":{"windows":{"2007":"a #4 #5","2010":"a #4 #5","2013":"a #4 #5","2016":"a #4 #5","2019":"a #4 #5"},"windows-mail":{"2021-11":"a #4"},"macos":{"16.56":"y","16.80":"y"},"outlook-com":{"2021-11":"y"},"ios":{"2021-11":"y"},"android":{"2021-11":"y"}},"samsung-email":{"android":{"7.0":"y"}},"sfr":{"desktop-webmail":{"2021-11":"y"},"ios":{"2021-11":"a #6"},"android":{"2021-11":"a #6"}},"thunderbird":{"macos":{"91.2.1":"y"}},"aol":{"desktop-webmail":{"2021-11":"a #7"},"ios":{"2021-11":"a #7"},"android":{"2021-11":"a #7"}},"yahoo":{"desktop-webmail":{"2021-11":"a #7"},"ios":{"2021-11":"a #7"},"android":{"2021-11":"a #7"}},"protonmail":{"desktop-webmail":{"2021-11":"a #8"},"ios":{"2021-11":"a #6"},"android":{"2021-11":"a #6"}},"hey":{"desktop-webmail":{"2021-11":"y"}},"mail-ru":{"desktop-webmail":{"2021-11":"y"}},"fastmail":{"desktop-webmail":{"2021-11":"y"}},"laposte":{"desktop-webmail":{"2021-11":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}},"wp-pl":{"desktop-webmail":{"2023-12":"n"}}},
"stats":{"apple-mail":{"macos":{"13":"y","15":"y"},"ios":{"15":"y"}},"gmail":{"desktop-webmail":{"2021-11":"a #1"},"ios":{"2021-11":"a #1 #2"},"android":{"2021-11":"a #1 #2"},"mobile-webmail":{"2021-11":"a #1 #2"}},"orange":{"desktop-webmail":{"2021-11":"n #3"},"ios":{"2021-11":"n #3"},"android":{"2021-11":"n #3"}},"outlook":{"windows":{"2007":"a #4 #5","2010":"a #4 #5","2013":"a #4 #5","2016":"a #4 #5","2019":"a #4 #5"},"windows-mail":{"2021-11":"a #4"},"macos":{"16.56":"y","16.80":"y"},"outlook-com":{"2021-11":"y"},"ios":{"2021-11":"y"},"android":{"2021-11":"y"}},"samsung-email":{"android":{"7.0":"y"}},"sfr":{"desktop-webmail":{"2021-11":"y"},"ios":{"2021-11":"a #6"},"android":{"2021-11":"a #6"}},"thunderbird":{"macos":{"91.2.1":"y"}},"aol":{"desktop-webmail":{"2021-11":"a #7"},"ios":{"2021-11":"a #7"},"android":{"2021-11":"a #7"}},"yahoo":{"desktop-webmail":{"2021-11":"a #7"},"ios":{"2021-11":"a #7"},"android":{"2021-11":"a #7"}},"protonmail":{"desktop-webmail":{"2021-11":"a #8"},"ios":{"2021-11":"a #6","2025-08":"a #9"},"android":{"2021-11":"a #6"}},"hey":{"desktop-webmail":{"2021-11":"y"}},"mail-ru":{"desktop-webmail":{"2021-11":"y"}},"fastmail":{"desktop-webmail":{"2021-11":"y"}},"laposte":{"desktop-webmail":{"2021-11":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}},"wp-pl":{"desktop-webmail":{"2023-12":"n"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported in lowercase. (See [email-bugs#13](https://github.com/hteumeuleu/email-bugs/issues/13))","2":"Partial. Only supported inline when using a Non Gmail Account due to the lack of `<style>` support.","3":"Not supported. The entire declaration is removed if there is no space before `!important`.","4":"Partial. Only supported with a space before.","5":"Partial. Not supported inline. (See [email-bugs#31](https://github.com/hteumeuleu/email-bugs/issues/31))","6":"Partial. Only supported inline due to the lack of `<style>` support.","7":"Partial. Removed if there is no space before when used with a `background-image` property. (See [email-bugs#16](https://github.com/hteumeuleu/email-bugs/issues/16))","8":"Partial. Only supported in lowercase."}
"notes_by_num":{"1":"Partial. Only supported in lowercase. (See [email-bugs#13](https://github.com/hteumeuleu/email-bugs/issues/13))","2":"Partial. Only supported inline when using a Non Gmail Account due to the lack of `<style>` support.","3":"Not supported. The entire declaration is removed if there is no space before `!important`.","4":"Partial. Only supported with a space before.","5":"Partial. Not supported inline. (See [email-bugs#31](https://github.com/hteumeuleu/email-bugs/issues/31))","6":"Partial. Only supported inline due to the lack of `<style>` support.","7":"Partial. Removed if there is no space before when used with a `background-image` property. (See [email-bugs#16](https://github.com/hteumeuleu/email-bugs/issues/16))","8":"Partial. Only supported in lowercase.","9":"Partial. Only supported if not written in lowercase."}
},
{
@@ -1161,7 +1177,7 @@
"description":"",
"url":"https://www.caniemail.com/features/css-inline-size/",
"category":"css",
"tags":[],
"tags":["i18n"],
"keywords":null,
"last_test_date":"2019-02-28",
"test_url":"https://www.caniemail.com/tests/css-box-model.html",
@@ -1337,7 +1353,7 @@
"description":null,
"url":"https://www.caniemail.com/features/css-list-style/",
"category":"css",
"tags":[],
"tags":["i18n"],
"keywords":null,
"last_test_date":"2020-04-20",
"test_url":"https://www.caniemail.com/tests/css-list.html",
@@ -1358,7 +1374,7 @@
"last_test_date":"2022-07-13",
"test_url":"https://www.caniemail.com/tests/css-margin-logical-properties.html",
"test_results_url":"https://testi.at/proj/qAmuL03Fg51cE6hkbNSVrXik",
"stats":{"apple-mail":{"macos":{"10.12.6":"n","10.13.6":"n","10.15.7":"y","12.4":"y"},"ios":{"11.4":"n","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"stats":{"apple-mail":{"macos":{"10.12.6":"n","10.13.6":"n","10.15.7":"y","12.4":"y"},"ios":{"11.4":"n","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -1390,7 +1406,7 @@
"last_test_date":"2022-07-13",
"test_url":"https://www.caniemail.com/tests/css-margin-logical-properties.html",
"test_results_url":"https://testi.at/proj/qAmuL03Fg51cE6hkbNSVrXik",
"stats":{"apple-mail":{"macos":{"10.12.6":"n","10.13.6":"n","10.15.7":"y","12.4":"y"},"ios":{"11.4":"n","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"stats":{"apple-mail":{"macos":{"10.12.6":"n","10.13.6":"n","10.15.7":"y","12.4":"y"},"ios":{"11.4":"n","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -1438,7 +1454,7 @@
"last_test_date":"2022-09-01",
"test_url":"https://www.caniemail.com/tests/css-max-block-size.html",
"test_results_url":"https://testi.at/proj/1y7SkPH3W7FPg0HwxS9lEiY",
"stats":{"apple-mail":{"macos":{"16":"y","17":"y","18":"y","19":"y","20":"y","21":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-08":"n"},"mobile-webmail":{"2022-07":"u"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2022-07":"y","16.80":"n"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"samsung-email":{"android":{"2022-09":"y"}},"protonmail":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}}},
"stats":{"apple-mail":{"macos":{"16":"y","17":"y","18":"y","19":"y","20":"y","21":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-08":"n"},"mobile-webmail":{"2022-07":"u"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2022-07":"y","16.80":"n"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"samsung-email":{"android":{"2022-09":"y"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}}},
"notes":null,
"notes_by_num":null
},
@@ -1470,7 +1486,7 @@
"last_test_date":"2024-05-31",
"test_url":"https://www.caniemail.com/tests/css-max-inline-size.html",
"test_results_url":"https://testi.at/proj/8r8g0dn81y8jc72z09",
"stats":{"apple-mail":{"macos":{"2024-05":"y"},"ios":{"2024-05":"y"}},"gmail":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"},"mobile-webmail":{"2024-05":"n"}},"orange":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-05":"n"},"macos":{"2024-05":"n"},"outlook-com":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"yahoo":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"aol":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"samsung-email":{"android":{"2024-05":"y"}},"sfr":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"protonmail":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"hey":{"desktop-webmail":{"2024-05":"u"}},"mail-ru":{"desktop-webmail":{"2024-05":"y"}},"fastmail":{"desktop-webmail":{"2024-05":"u"}},"laposte":{"desktop-webmail":{"2021-08":"u"}},"gmx":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"web-de":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-05":"u"},"android":{"2024-05":"u"}}},
"stats":{"apple-mail":{"macos":{"2024-05":"y"},"ios":{"2024-05":"y"}},"gmail":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"},"mobile-webmail":{"2024-05":"n"}},"orange":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-05":"n"},"macos":{"2024-05":"n"},"outlook-com":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"yahoo":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"aol":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"samsung-email":{"android":{"2024-05":"y"}},"sfr":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"protonmail":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"hey":{"desktop-webmail":{"2024-05":"u"}},"mail-ru":{"desktop-webmail":{"2024-05":"y"}},"fastmail":{"desktop-webmail":{"2024-05":"u"}},"laposte":{"desktop-webmail":{"2021-08":"u"}},"gmx":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"web-de":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-05":"u"},"android":{"2024-05":"u"}}},
"notes":null,
"notes_by_num":null
},
@@ -1486,7 +1502,7 @@
"last_test_date":"2019-08-02",
"test_url":"https://www.caniemail.com/tests/css-width-height.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/dP8XNPcCLZGrogYGvFgCRRjJJO2nTWxchQ0WZSu0Pxcyb/list",
"stats":{"apple-mail":{"macos":{"10.3":"y"},"ios":{"5.1":"a #2","6.1":"a #2","10.3":"y","12.2":"y"}},"gmail":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"},"mobile-webmail":{"2020-02":"y"}},"orange":{"desktop-webmail":{"2019-08":"y","2021-03":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"outlook":{"windows":{"2003":"a #2","2007":"n","2010":"n","2013":"n","2016":"n","2019":"a #1"},"windows-mail":{"2020-01":"a #1"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-08":"y","2024-01":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"thunderbird":{"macos":{"60.7":"y"}},"aol":{"desktop-webmail":{"2020-01":"y"},"ios":{"2020-01":"a #2"},"android":{"2020-01":"y"}},"yahoo":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"a #2"},"android":{"2019-08":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"a #2"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"10.3":"y"},"ios":{"5.1":"a #2","6.1":"a #2","10.3":"y","12.2":"y"}},"gmail":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"},"mobile-webmail":{"2020-02":"y"}},"orange":{"desktop-webmail":{"2019-08":"y","2021-03":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"outlook":{"windows":{"2003":"a #2","2007":"n","2010":"n","2013":"n","2016":"n","2019":"a #1"},"windows-mail":{"2020-01":"a #1"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-08":"y","2024-01":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"thunderbird":{"macos":{"60.7":"y"}},"aol":{"desktop-webmail":{"2020-01":"y"},"ios":{"2020-01":"a #2","2025-11":"y"},"android":{"2020-01":"y"}},"yahoo":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"a #2","2025-11":"y"},"android":{"2019-08":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"a #2","2025-11":"y"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only works on `<table>` elements.","2":"Partial. Doesn't work on `<table>` elements, as per [CSS 2.1 specification](https://www.w3.org/TR/CSS2/visudet.html#min-max-widths)."}
},
@@ -1502,7 +1518,7 @@
"last_test_date":"2024-05-31",
"test_url":"https://www.caniemail.com/tests/css-min-block-size.html",
"test_results_url":"https://testi.at/proj/73yg05zgtpk3cez6ua5",
"stats":{"apple-mail":{"macos":{"2024-05":"y"},"ios":{"2024-05":"y"}},"gmail":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"},"mobile-webmail":{"2024-05":"n"}},"orange":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-05":"n"},"macos":{"2024-05":"n"},"outlook-com":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"yahoo":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"aol":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"samsung-email":{"android":{"2024-05":"y"}},"sfr":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"protonmail":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"hey":{"desktop-webmail":{"2024-05":"u"}},"mail-ru":{"desktop-webmail":{"2024-05":"y"}},"fastmail":{"desktop-webmail":{"2024-05":"u"}},"laposte":{"desktop-webmail":{"2021-08":"u"}},"gmx":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"web-de":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-05":"u"},"android":{"2024-05":"u"}}},
"stats":{"apple-mail":{"macos":{"2024-05":"y"},"ios":{"2024-05":"y"}},"gmail":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"},"mobile-webmail":{"2024-05":"n"}},"orange":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-05":"n"},"macos":{"2024-05":"n"},"outlook-com":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"yahoo":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"aol":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"samsung-email":{"android":{"2024-05":"y"}},"sfr":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"protonmail":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"hey":{"desktop-webmail":{"2024-05":"u"}},"mail-ru":{"desktop-webmail":{"2024-05":"y"}},"fastmail":{"desktop-webmail":{"2024-05":"u"}},"laposte":{"desktop-webmail":{"2021-08":"u"}},"gmx":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"web-de":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-05":"u"},"android":{"2024-05":"u"}}},
"notes":null,
"notes_by_num":null
},
@@ -1534,7 +1550,7 @@
"last_test_date":"2022-08-30",
"test_url":"https://www.caniemail.com/tests/css-min-inline-size.html",
"test_results_url":"https://testi.at/proj/6m0cx5puENPh8pLi9rpSPzJSB",
"stats":{"apple-mail":{"macos":{"16":"y","17":"y","18":"y","19":"y","20":"y","21":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-08":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2022-07":"y","16.80":"n"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"samsung-email":{"android":{"2022-07":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"protonmail":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}}},
"stats":{"apple-mail":{"macos":{"16":"y","17":"y","18":"y","19":"y","20":"y","21":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-08":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2022-07":"y","16.80":"n"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"samsung-email":{"android":{"2022-07":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}}},
"notes":null,
"notes_by_num":null
},
@@ -1598,9 +1614,9 @@
"last_test_date":"2023-08-31",
"test_url":"https://www.caniemail.com/tests/css-nesting.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/8z9ecWkyaSHebmYl0r6dlWFfcia0VNfeKu6s01l5Fw3M0/list",
"stats":{"apple-mail":{"macos":{"16.0":"a #1"},"ios":{"16.6":"a #1","17.2":"y"}},"gmail":{"desktop-webmail":{"2023-08":"n"},"ios":{"2023-08":"n"},"android":{"2023-08":"n"},"mobile-webmail":{"2023-08":"n"}},"orange":{"desktop-webmail":{"2023-08":"a #2"},"ios":{"2023-08":"a #2"},"android":{"2023-08":"u"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2023-08":"n"},"macos":{"16.78":"a #1","16.80":"n"},"outlook-com":{"2023-08":"n","2024-01":"n"},"ios":{"2023-08":"n"},"android":{"2024-03":"n"}},"samsung-email":{"android":{"6.0":"u","6.1.90.16":"a #4"}},"sfr":{"desktop-webmail":{"2023-08":"a #1 #2"},"ios":{"2023-08":"n"},"android":{"2023-08":"u"}},"thunderbird":{"macos":{"102.15":"n","137.0b3":"y"}},"aol":{"desktop-webmail":{"2024-01":"n #3"},"ios":{"2023-08":"u"},"android":{"2023-08":"u"}},"yahoo":{"desktop-webmail":{"2023-08":"n #3"},"ios":{"2023-08":"n #3"},"android":{"2024-03":"n #3"}},"protonmail":{"desktop-webmail":{"2023-08":"u"},"ios":{"2023-08":"u"},"android":{"2023-08":"u"}},"hey":{"desktop-webmail":{"2023-08":"u"}},"mail-ru":{"desktop-webmail":{"2024-01":"n"}},"fastmail":{"desktop-webmail":{"2023-08":"u"}},"laposte":{"desktop-webmail":{"2023-08":"u"}},"free-fr":{"desktop-webmail":{"2023-08":"u"}},"t-online-de":{"desktop-webmail":{"2023-08":"u"}},"gmx":{"desktop-webmail":{"2021-12":"u"},"ios":{"2021-12":"u"},"android":{"2021-12":"u"}},"web-de":{"desktop-webmail":{"2021-12":"u"},"ios":{"2021-12":"u"},"android":{"2021-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2021-12":"u"},"android":{"2021-12":"u"}}},
"stats":{"apple-mail":{"macos":{"16.0":"a #1"},"ios":{"16.6":"a #1","17.2":"y"}},"gmail":{"desktop-webmail":{"2023-08":"n"},"ios":{"2023-08":"n"},"android":{"2023-08":"n"},"mobile-webmail":{"2023-08":"n"}},"orange":{"desktop-webmail":{"2023-08":"a #2"},"ios":{"2023-08":"a #2"},"android":{"2023-08":"u"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2023-08":"n"},"macos":{"16.78":"a #1","16.80":"n"},"outlook-com":{"2023-08":"n","2024-01":"n"},"ios":{"2023-08":"n"},"android":{"2024-03":"n"}},"samsung-email":{"android":{"6.0":"u","6.1.90.16":"a #4"}},"sfr":{"desktop-webmail":{"2023-08":"a #1 #2"},"ios":{"2023-08":"n"},"android":{"2023-08":"u"}},"thunderbird":{"macos":{"102.15":"n","137.0b3":"y"}},"aol":{"desktop-webmail":{"2024-01":"n #3"},"ios":{"2023-08":"u"},"android":{"2023-08":"u"}},"yahoo":{"desktop-webmail":{"2023-08":"n #3"},"ios":{"2023-08":"n #3"},"android":{"2024-03":"n #3"}},"protonmail":{"desktop-webmail":{"2023-08":"y"},"ios":{"2023-08":"a #5"},"android":{"2023-08":"a #5"}},"hey":{"desktop-webmail":{"2023-08":"u"}},"mail-ru":{"desktop-webmail":{"2024-01":"n"}},"fastmail":{"desktop-webmail":{"2023-08":"u"}},"laposte":{"desktop-webmail":{"2023-08":"u"}},"free-fr":{"desktop-webmail":{"2023-08":"u"}},"t-online-de":{"desktop-webmail":{"2023-08":"u"}},"gmx":{"desktop-webmail":{"2021-12":"u"},"ios":{"2021-12":"u"},"android":{"2021-12":"u"}},"web-de":{"desktop-webmail":{"2021-12":"u"},"ios":{"2021-12":"u"},"android":{"2021-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2021-12":"u"},"android":{"2021-12":"u"}}},
"notes":null,
"notes_by_num":{"1":"Partial. `E { F {}}` doesnt work, but `E { & F {}}` does. Full support was added in macOS 14.2.","2":"Buggy. The syntax is supported, but nested selectors are prefixed by the webmail, which might invalidate the selector.","3":"Not supported. The nested selectors are removed, making the nested properties apply to the parent selector.","4":"Partial. Not supported with Hotmail/Outlook accounts."}
"notes_by_num":{"1":"Partial. `E { F {}}` doesnt work, but `E { & F {}}` does. Full support was added in macOS 14.2.","2":"Buggy. The syntax is supported, but nested selectors are prefixed by the webmail, which might invalidate the selector.","3":"Not supported. The nested selectors are removed, making the nested properties apply to the parent selector.","4":"Partial. Not supported with Hotmail/Outlook accounts.","5":"Partial. `@media` is not fully supported, and `& & &` syntax not supported"}
},
{
@@ -1646,7 +1662,7 @@
"last_test_date":"2019-02-28",
"test_url":"https://www.caniemail.com/tests/css-visual-effects.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/DhTRmGsVH6uobU4pHD3CasJywfBL4HnEjA1LOF8f9ctso/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"12.1":"y"}},"gmail":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-08":"y","2021-03":"n","2024-04":"n"},"ios":{"2019-08":"y","2024-04":"n"},"android":{"2019-08":"y","2024-04":"n"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-02":"n"},"macos":{"2019-02":"y","16.80":"y"},"outlook-com":{"2019-02":"y","2024-01":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"}},"thunderbird":{"macos":{"60.8":"y"}},"yahoo":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"}},"aol":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"}},"samsung-email":{"android":{"5.0.10.2":"y"}},"sfr":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"y"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"12.1":"y"}},"gmail":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-08":"y","2021-03":"n","2024-04":"n"},"ios":{"2019-08":"y","2024-04":"n"},"android":{"2019-08":"y","2024-04":"n"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-02":"n"},"macos":{"2019-02":"y","16.80":"y"},"outlook-com":{"2019-02":"y","2024-01":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"}},"thunderbird":{"macos":{"60.8":"y"}},"yahoo":{"desktop-webmail":{"2019-02":"n","2025-06":"y"},"ios":{"2019-02":"n","2025-06":"y"},"android":{"2019-02":"n","2025-06":"y"}},"aol":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"}},"samsung-email":{"android":{"5.0.10.2":"y"}},"sfr":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"y"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -1662,7 +1678,7 @@
"last_test_date":"2024-06-13",
"test_url":"https://www.caniemail.com/tests/css-widows.html",
"test_results_url":"https://testi.at/proj/6vd8udzx1b5l1vrnsr",
"stats":{"apple-mail":{"macos":{"2024-05":"y"},"ios":{"2024-05":"y"}},"gmail":{"desktop-webmail":{"2024-05":"n #4"},"ios":{"2024-05":"n"},"android":{"2024-05":"n #3"},"mobile-webmail":{"2024-05":"n #1 #2"}},"orange":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-05":"n"},"macos":{"2024-05":"y"},"outlook-com":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"yahoo":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"aol":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"samsung-email":{"android":{"2024-05":"y"}},"sfr":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"protonmail":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"hey":{"desktop-webmail":{"2024-05":"u"}},"mail-ru":{"desktop-webmail":{"2024-05":"y #4"}},"fastmail":{"desktop-webmail":{"2024-05":"u"}},"laposte":{"desktop-webmail":{"2021-08":"u"}},"gmx":{"desktop-webmail":{"2024-05":"n #1 #4"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"web-de":{"desktop-webmail":{"2024-05":"n #1 #4"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-05":"u"},"android":{"2024-05":"u"}}},
"stats":{"apple-mail":{"macos":{"2024-05":"y"},"ios":{"2024-05":"y"}},"gmail":{"desktop-webmail":{"2024-05":"n #4"},"ios":{"2024-05":"n"},"android":{"2024-05":"n #3"},"mobile-webmail":{"2024-05":"n #1 #2"}},"orange":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-05":"n"},"macos":{"2024-05":"y"},"outlook-com":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"yahoo":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"aol":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"samsung-email":{"android":{"2024-05":"y"}},"sfr":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"protonmail":{"desktop-webmail":{"2024-05":"y #4"},"ios":{"2024-05":"y #4"},"android":{"2024-05":"y #4"}},"hey":{"desktop-webmail":{"2024-05":"u"}},"mail-ru":{"desktop-webmail":{"2024-05":"y #4"}},"fastmail":{"desktop-webmail":{"2024-05":"u"}},"laposte":{"desktop-webmail":{"2021-08":"u"}},"gmx":{"desktop-webmail":{"2024-05":"n #1 #4"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"web-de":{"desktop-webmail":{"2024-05":"n #1 #4"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-05":"u"},"android":{"2024-05":"u"}}},
"notes":null,
"notes_by_num":{"1":"Buggy. `columns` property is stripped which is required for `orphans` to work","2":"Buggy. `orphans` property value is replaced by `auto`","3":"Not supported, but Gmail's default styles on the email message container includes the `orphans` property. These values are inherited by children elements","4":"Webmail rendering depends on browser support"}
},
@@ -1723,10 +1739,10 @@
"category":"css",
"tags":[],
"keywords":"overflow-block, overflow-inline",
"last_test_date":"2024-10-02",
"last_test_date":"2025-05-27",
"test_url":"https://www.caniemail.com/tests/css-box-model.html",
"test_results_url":"https://testi.at/proj/p4rru3ez069p15p6ij",
"stats":{"apple-mail":{"macos":{"12.4":"a #1","2024-10":"a #4"},"ios":{"12.1":"y","2024-10":"a #4"}},"gmail":{"desktop-webmail":{"2019-02":"y","2024-10":"a #4"},"ios":{"2019-02":"y","2024-10":"a #4"},"android":{"2019-02":"y","2024-10":"a #4"},"mobile-webmail":{"2020-02":"y","2024-10":"a #4"}},"orange":{"desktop-webmail":{"2019-08":"n #2","2021-03":"y","2024-10":"a #3"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2019-02":"n"},"macos":{"2019-02":"y","16.80":"y","2024-10":"a #4"},"outlook-com":{"2019-02":"y","2024-01":"y","2024-10":"a #3"},"ios":{"2019-02":"y","2024-10":"a #4"},"android":{"2019-02":"n"}},"yahoo":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y","2024-10":"a #4"},"android":{"2019-02":"n"}},"aol":{"desktop-webmail":{"2019-02":"y","2024-10":"a #4"},"ios":{"2019-02":"y","2024-10":"a #4"},"android":{"2019-02":"n"}},"samsung-email":{"android":{"5.0.10.2":"y","2024-10":"a #4"}},"sfr":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"thunderbird":{"macos":{"60.5":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"y"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y","2024-10":"a #3"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"y","2024-10":"a #3"},"ios":{"2022-06":"y","2024-10":"a #3"},"android":{"2022-06":"y","2024-10":"a #3"}},"web-de":{"desktop-webmail":{"2022-06":"y","2024-10":"a #3"},"ios":{"2022-06":"y","2024-10":"a #3"},"android":{"2022-06":"y","2024-10":"a #3"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"test_results_url":"https://testi.at/proj/278gsp8afyl8f6nbu4",
"stats":{"apple-mail":{"macos":{"12.4":"a #1","2024-10":"a #4"},"ios":{"12.1":"y","2024-10":"a #4"}},"gmail":{"desktop-webmail":{"2019-02":"y","2024-10":"a #4"},"ios":{"2019-02":"y","2024-10":"a #4"},"android":{"2019-02":"y","2024-10":"a #4","2025-07":"a #1 #4"},"mobile-webmail":{"2020-02":"y","2024-10":"a #4"}},"orange":{"desktop-webmail":{"2019-08":"n #2","2021-03":"y","2024-10":"a #3"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n","2024":"n"},"windows-mail":{"2019-02":"n"},"macos":{"2019-02":"y","16.80":"y","2024-10":"a #4"},"outlook-com":{"2019-02":"y","2024-01":"y","2024-10":"a #3","2025-05":"a #4"},"ios":{"2019-02":"y","2024-10":"a #4"},"android":{"2019-02":"n","2025-05":"a #1 #4"}},"yahoo":{"desktop-webmail":{"2019-02":"y","2025-05":"a #4"},"ios":{"2019-02":"y","2024-10":"a #4"},"android":{"2019-02":"n","2025-05":"a #1 #4"}},"aol":{"desktop-webmail":{"2019-02":"y","2024-10":"a #4"},"ios":{"2019-02":"y","2024-10":"a #4"},"android":{"2019-02":"n","2025-07":"a #1 #4"}},"samsung-email":{"android":{"5.0.10.2":"y","2024-10":"a #4"}},"sfr":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"thunderbird":{"macos":{"60.5":"y","138":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"y","2025-07":"a #3"},"ios":{"2020-03":"y","2025-07":"a #3"},"android":{"2020-03":"y","2025-07":"a #1 #3"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y","2024-10":"a #3"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"y","2024-10":"a #3"},"ios":{"2022-06":"y","2024-10":"a #3"},"android":{"2022-06":"y","2024-10":"a #3","2025-07":"a #1 #3"}},"web-de":{"desktop-webmail":{"2022-06":"y","2024-10":"a #3"},"ios":{"2022-06":"y","2024-10":"a #3"},"android":{"2022-06":"y","2024-10":"a #3"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Buggy. Cannot scroll through to hidden content.","2":"Not supported. `overflow` is replaced by `java-script`.","3":"Partial. Support for `overflow-block` & `overflow-inline` depends on browser support.","4":"Partial. `overflow-block` & `overflow-inline` not supported."}
},
@@ -1742,7 +1758,7 @@
"last_test_date":"2022-07-13",
"test_url":"https://www.caniemail.com/tests/css-padding-logical-properties.html",
"test_results_url":"https://testi.at/proj/Y91uDXJIDLc6M0FkVXipW",
"stats":{"apple-mail":{"macos":{"10.12.6":"n","10.13.6":"n","10.15.7":"y","12.4":"y"},"ios":{"11.4":"n","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"stats":{"apple-mail":{"macos":{"10.12.6":"n","10.13.6":"n","10.15.7":"y","12.4":"y"},"ios":{"11.4":"n","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -1758,7 +1774,7 @@
"last_test_date":"2022-07-13",
"test_url":"https://www.caniemail.com/tests/css-padding-logical-properties.html",
"test_results_url":"https://testi.at/proj/Y91uDXJIDLc6M0FkVXipW",
"stats":{"apple-mail":{"macos":{"10.12.6":"n","10.13.6":"n","10.15.7":"n","12.4":"y"},"ios":{"11.4":"n","12":"n","13":"n","14":"n","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"n","2016":"n","16.80":"n"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"n","11":"n"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"stats":{"apple-mail":{"macos":{"10.12.6":"n","10.13.6":"n","10.15.7":"n","12.4":"y"},"ios":{"11.4":"n","12":"n","13":"n","14":"n","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"n","2016":"n","16.80":"n"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"n","11":"n"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -1774,7 +1790,7 @@
"last_test_date":"2022-07-13",
"test_url":"https://www.caniemail.com/tests/css-padding-logical-properties.html",
"test_results_url":"https://testi.at/proj/Y91uDXJIDLc6M0FkVXipW",
"stats":{"apple-mail":{"macos":{"10.12.6":"n","10.13.6":"n","10.15.7":"y","12.4":"y"},"ios":{"11.4":"n","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"stats":{"apple-mail":{"macos":{"10.12.6":"n","10.13.6":"n","10.15.7":"y","12.4":"y"},"ios":{"11.4":"n","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"60.3":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -1822,7 +1838,7 @@
"last_test_date":"2019-10-28",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"n","16":"a #2"},"ios":{"13.1":"n"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2019-02":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"n"},"android":{"2019-10":"y"}},"thunderbird":{"macos":{"60.8":"y"}},"yahoo":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"}},"aol":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"n"},"android":{"2019-02":"y"}},"samsung-email":{"android":{"6.0.04.6":"n"}},"sfr":{"desktop-webmail":{"2020-01":"y"},"ios":{"2020-01":"n"},"android":{"2020-01":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"n","16":"a #2"},"ios":{"13.1":"n"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2019-02":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"n"},"android":{"2019-10":"y"}},"thunderbird":{"macos":{"60.8":"y"}},"yahoo":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"}},"aol":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"n"},"android":{"2019-02":"y"}},"samsung-email":{"android":{"6.0.04.6":"n"}},"sfr":{"desktop-webmail":{"2020-01":"y","2025-07":"n"},"ios":{"2020-01":"n"},"android":{"2020-01":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"y"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported on type selectors.","2":"Partial. Supported with mouse clicks. Not supported with keyboard input."}
},
@@ -1838,11 +1854,27 @@
"last_test_date":"2020-03-10",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/jRZRnTXxdqCwNM60saxYK4Ee7783SAj1qQKytJlOoB7dO/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.3":"y"}},"gmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"},"mobile-webmail":{"2020-03":"n"}},"orange":{"desktop-webmail":{"2020-03":"n #2","2021-03":"n #2"},"ios":{"2020-03":"n #2"},"android":{"2020-03":"n #2"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-03":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2020-03":"a #1","2024-01":"a #1"},"ios":{"2020-03":"a #1"},"android":{"2020-03":"a #1"}},"samsung-email":{"android":{"7.0":"y"}},"sfr":{"desktop-webmail":{"2020-03":"n #2"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"}},"thunderbird":{"macos":{"68.5":"y"}},"aol":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"y"},"android":{"2020-03":"y"}},"yahoo":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"y"},"android":{"2020-03":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"}},"hey":{"desktop-webmail":{"2020-06":"n"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"n #2"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"n"},"android":{"2022-07":"n"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.3":"y"}},"gmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"},"mobile-webmail":{"2020-03":"n"}},"orange":{"desktop-webmail":{"2020-03":"n #2","2021-03":"n #2"},"ios":{"2020-03":"n #2"},"android":{"2020-03":"n #2"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-03":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2020-03":"a #1","2024-01":"a #1"},"ios":{"2020-03":"a #1"},"android":{"2020-03":"a #1"}},"samsung-email":{"android":{"7.0":"y"}},"sfr":{"desktop-webmail":{"2020-03":"n #2","2025-07":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"}},"thunderbird":{"macos":{"68.5":"y"}},"aol":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"y"},"android":{"2020-03":"y"}},"yahoo":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"y"},"android":{"2020-03":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"}},"hey":{"desktop-webmail":{"2020-06":"n"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"n #2","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"n"},"android":{"2022-07":"n"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported on type selectors.","2":"Not supported. `<input>` elements are transformed into `<noinput>`."}
},
{
"slug":"css-pseudo-class-default",
"title":":default",
"description":"Selects form elements that are the default in a group of related elements.",
"url":"https://www.caniemail.com/features/css-pseudo-class-default/",
"category":"css",
"tags":["accessibility"],
"keywords":"pseudo-class, form",
"last_test_date":"2026-02-05",
"test_url":"https://www.caniemail.com/tests/css-pseudo-class-default.html",
"test_results_url":"https://testi.at/proj/7ov4sbxz1krv07gkf5",
"stats":{"apple-mail":{"macos":{"12":"y","26":"y"},"ios":{"11":"y","26":"y"}},"gmail":{"desktop-webmail":{"2026-02":"n"},"ios":{"2026-02":"n"},"android":{"2026-02":"n"},"mobile-webmail":{"2026-02":"n"}},"orange":{"desktop-webmail":{"2026-02":"u"},"ios":{"2026-02":"u"},"android":{"2026-02":"u"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n","2024":"n"},"windows-mail":{"2026-02":"n"},"macos":{"16.105.2":"y"},"outlook-com":{"2026-02":"a #1"},"ios":{"2026-02":"y"},"android":{"2026-02":"y"}},"samsung-email":{"android":{"6.0":"u"}},"sfr":{"desktop-webmail":{"2026-02":"u"},"ios":{"2026-02":"u"},"android":{"2026-02":"u"}},"thunderbird":{"macos":{"147.0.1":"y"}},"aol":{"desktop-webmail":{"2026-02":"y"},"ios":{"2026-02":"y"},"android":{"2026-02":"y"}},"yahoo":{"desktop-webmail":{"2026-02":"y"},"ios":{"2026-02":"y"},"android":{"2026-02":"y"}},"protonmail":{"desktop-webmail":{"2026-02":"n"},"ios":{"2026-02":"n"},"android":{"2026-02":"n"}},"hey":{"desktop-webmail":{"2026-02":"u"}},"mail-ru":{"desktop-webmail":{"2026-02":"y"}},"fastmail":{"desktop-webmail":{"2026-02":"u"}},"laposte":{"desktop-webmail":{"2026-02":"u"}},"free-fr":{"desktop-webmail":{"2026-02":"u"}},"t-online-de":{"desktop-webmail":{"2026-02":"n"}},"gmx":{"desktop-webmail":{"2026-02":"n"},"ios":{"2026-02":"y"},"android":{"2026-02":"n"}},"web-de":{"desktop-webmail":{"2026-02":"n"},"ios":{"2026-02":"u"},"android":{"2026-02":"u"}},"ionos-1and1":{"desktop-webmail":{"2026-02":"u"},"android":{"2026-02":"u"}}},
"notes":"Depends on device/browser support. Some devices/browsers do not support styling on &lt;option&gt;.",
"notes_by_num":{"1":"Works on input[radio] and input[checkbox] only."}
},
{
"slug":"css-pseudo-class-first-child",
"title":":first-child",
@@ -1854,7 +1886,7 @@
"last_test_date":"2019-10-16",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y","2025-07":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported on type selectors."}
},
@@ -1870,7 +1902,7 @@
"last_test_date":"2019-10-16",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y","2025-07":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported on type selectors."}
},
@@ -1886,7 +1918,7 @@
"last_test_date":"2019-10-28",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"n","16":"y"},"ios":{"13.1":"n"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2019-02":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"n"},"android":{"2019-10":"y"}},"thunderbird":{"macos":{"60.8":"y"}},"yahoo":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"}},"aol":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"n"},"android":{"2019-02":"y"}},"samsung-email":{"android":{"6.0.04.6":"y"}},"sfr":{"desktop-webmail":{"2020-01":"y"},"ios":{"2020-01":"n"},"android":{"2020-01":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"n"}}},
"stats":{"apple-mail":{"macos":{"12.4":"n","16":"y"},"ios":{"13.1":"n"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2019-02":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"n"},"android":{"2019-10":"y"}},"thunderbird":{"macos":{"60.8":"y"}},"yahoo":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"}},"aol":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"n"},"android":{"2019-02":"y"}},"samsung-email":{"android":{"6.0.04.6":"y"}},"sfr":{"desktop-webmail":{"2020-01":"y","2025-07":"n"},"ios":{"2020-01":"n"},"android":{"2020-01":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"y"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"n"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported on type selectors."}
},
@@ -1902,7 +1934,7 @@
"last_test_date":"2022-03-15",
"test_url":"https://www.caniemail.com/tests/css-has.html",
"test_results_url":"",
"stats":{"apple-mail":{"macos":{"15.0":"n","16.0":"y"},"ios":{"15.1":"n","15.4":"y"}},"gmail":{"desktop-webmail":{"2021-12":"n","2023-09":"n"},"ios":{"2021-12":"n","2023-09":"n"},"android":{"2021-12":"n","2023-09":"n"},"mobile-webmail":{"2021-12":"n"}},"orange":{"desktop-webmail":{"2021-12":"y"},"ios":{"2021-12":"n"},"android":{"2021-12":"n"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2021-12":"n"},"macos":{"16.56":"n","16.73":"y","16.80":"n"},"outlook-com":{"2021-12":"n","2023-09":"n","2024-01":"n"},"ios":{"2021-12":"n","2023-09":"n"},"android":{"2021-12":"n"}},"samsung-email":{"android":{"6.0":"n","6.1.82":"y"}},"sfr":{"desktop-webmail":{"2021-12":"y"},"ios":{"2021-12":"n"},"android":{"2021-12":"n"}},"thunderbird":{"macos":{"78.14":"n","115.2":"n"}},"aol":{"desktop-webmail":{"2021-12":"n #1"},"ios":{"2021-12":"n"},"android":{"2021-12":"n"}},"yahoo":{"desktop-webmail":{"2021-12":"n #1","2023-09":"n #1"},"ios":{"2021-12":"n","2023-09":"n"},"android":{"2021-12":"n","2023-09":"n"}},"protonmail":{"desktop-webmail":{"2021-12":"n #2","2023-09":"y"},"ios":{"2021-12":"n","2023-09":"y"},"android":{"2021-12":"n","2023-09":"n"}},"hey":{"desktop-webmail":{"2021-12":"y"}},"mail-ru":{"desktop-webmail":{"2021-12":"n","2023-09":"n"}},"fastmail":{"desktop-webmail":{"2021-12":"n","2023-09":"y"}},"laposte":{"desktop-webmail":{"2021-12":"y"}},"gmx":{"desktop-webmail":{"2022-07":"n","2023-09":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"15.0":"n","16.0":"y"},"ios":{"15.1":"n","15.4":"y"}},"gmail":{"desktop-webmail":{"2021-12":"n","2023-09":"n"},"ios":{"2021-12":"n","2023-09":"n"},"android":{"2021-12":"n","2023-09":"n"},"mobile-webmail":{"2021-12":"n"}},"orange":{"desktop-webmail":{"2021-12":"y"},"ios":{"2021-12":"n"},"android":{"2021-12":"n"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2021-12":"n"},"macos":{"16.56":"n","16.73":"y","16.80":"n"},"outlook-com":{"2021-12":"n","2023-09":"n","2024-01":"n"},"ios":{"2021-12":"n","2023-09":"n"},"android":{"2021-12":"n"}},"samsung-email":{"android":{"6.0":"n","6.1.82":"y"}},"sfr":{"desktop-webmail":{"2021-12":"y","2025-07":"n"},"ios":{"2021-12":"n"},"android":{"2021-12":"n"}},"thunderbird":{"macos":{"78.14":"n","115.2":"n"}},"aol":{"desktop-webmail":{"2021-12":"n #1"},"ios":{"2021-12":"n"},"android":{"2021-12":"n"}},"yahoo":{"desktop-webmail":{"2021-12":"n #1","2023-09":"n #1"},"ios":{"2021-12":"n","2023-09":"n"},"android":{"2021-12":"n","2023-09":"n"}},"protonmail":{"desktop-webmail":{"2021-12":"n #2","2023-09":"y"},"ios":{"2021-12":"n","2023-09":"y"},"android":{"2021-12":"n","2023-09":"n"}},"hey":{"desktop-webmail":{"2021-12":"y"}},"mail-ru":{"desktop-webmail":{"2021-12":"n","2023-09":"n"}},"fastmail":{"desktop-webmail":{"2021-12":"n","2023-09":"y"}},"laposte":{"desktop-webmail":{"2021-12":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"n","2023-09":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":"As of december 2021, `:has()` is only supported in [Safari Technology Preview 137](https://webkit.org/blog/12156/release-notes-for-safari-technology-preview-137/). As of march 2022, it is supported in Safari 15.4.",
"notes_by_num":{"1":"Not supported. `:has(…)` is replaced by `:has`.","2":"Not supported. But the pseudo-class seems interpreted and computed server side."}
},
@@ -1918,7 +1950,7 @@
"last_test_date":"2019-10-23",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"12.1":"y","13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2019-02":"y","16.80":"a #2"},"outlook-com":{"2019-10":"a #2","2024-01":"a #2"},"ios":{"2019-10":"n"},"android":{"2019-10":"y"}},"thunderbird":{"macos":{"60.8":"y"}},"yahoo":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"}},"aol":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"n"},"android":{"2019-02":"y"}},"samsung-email":{"android":{"5.0.10.2":"y","6.0.04.6":"y"}},"sfr":{"desktop-webmail":{"2020-01":"y"},"ios":{"2020-01":"n"},"android":{"2020-01":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"12.1":"y","13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2019-02":"y","16.80":"a #2"},"outlook-com":{"2019-10":"a #2","2024-01":"a #2"},"ios":{"2019-10":"n"},"android":{"2019-10":"y"}},"thunderbird":{"macos":{"60.8":"y"}},"yahoo":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"}},"aol":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"n"},"android":{"2019-02":"y"}},"samsung-email":{"android":{"5.0.10.2":"y","6.0.04.6":"y"}},"sfr":{"desktop-webmail":{"2020-01":"y","2025-07":"n"},"ios":{"2020-01":"n"},"android":{"2020-01":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"y"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Not supported with non Google accounts.","2":"Partial. Only supported on type selectors."}
},
@@ -1934,7 +1966,7 @@
"last_test_date":"2022-07-12",
"test_url":"https://www.caniemail.com/tests/css-pseudo-selectors-lang.html",
"test_results_url":"https://testi.at/proj/gGZHWn1FNVBHweeCPYAFL4MSXy",
"stats":{"apple-mail":{"macos":{"15":"y"},"ios":{"15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"16.56":"y","16.80":"n"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"78.14":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"n"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}}},
"stats":{"apple-mail":{"macos":{"15":"y"},"ios":{"15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"16.56":"y","16.80":"n"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"samsung-email":{"android":{"10":"y","11":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u","2025-07":"n"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"78.14":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"n"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u","2025-07":"n"}}},
"notes":null,
"notes_by_num":null
},
@@ -1950,7 +1982,7 @@
"last_test_date":"2019-10-19",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y","2025-07":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported on type selectors."}
},
@@ -1966,7 +1998,7 @@
"last_test_date":"2019-10-19",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y","2025-07":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported on type selectors."}
},
@@ -1982,7 +2014,7 @@
"last_test_date":"2019-10-23",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"y","2010":"y","2013":"y","2016":"y","2019":"y"},"windows-mail":{"2019-10":"y"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2019-10":"y","2024-01":"a #1"},"ios":{"2.51.1":"y","4.7.1":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"y","2010":"y","2013":"y","2016":"y","2019":"y"},"windows-mail":{"2019-10":"y"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2019-10":"y","2024-01":"a #1"},"ios":{"2.51.1":"y","4.7.1":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y","2025-07":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -1998,7 +2030,7 @@
"last_test_date":"2019-10-23",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2019-10":"n","2024-01":"n"},"ios":{"2.51.1":"y","4.7.1":"n"},"android":{"2019-10":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"yahoo":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2019-10":"n","2024-01":"n"},"ios":{"2.51.1":"y","4.7.1":"n"},"android":{"2019-10":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y","2025-07":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"yahoo":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -2014,7 +2046,7 @@
"last_test_date":"2019-10-19",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2019-10":"a #1","2024-01":"n"},"ios":{"2.51.1":"y","4.7.1":"n"},"android":{"2019-10":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"yahoo":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2019-10":"a #1","2024-01":"n"},"ios":{"2.51.1":"y","4.7.1":"n"},"android":{"2019-10":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y","2025-07":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"yahoo":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported on type selectors.","2":"Not supported. Removes the parenthesis part."}
},
@@ -2030,7 +2062,7 @@
"last_test_date":"2019-10-19",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2019-10":"a #1","2024-01":"n"},"ios":{"2.51.1":"y","4.7.1":"n"},"android":{"2019-10":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"yahoo":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2019-10":"a #1","2024-01":"n"},"ios":{"2.51.1":"y","4.7.1":"n"},"android":{"2019-10":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y","2025-07":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"yahoo":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported on type selectors.","2":"Not supported. Removes the parenthesis part."}
},
@@ -2046,7 +2078,7 @@
"last_test_date":"2019-10-19",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2019-10":"a #1","2024-01":"n"},"ios":{"2.51.1":"y","4.7.1":"n"},"android":{"2019-10":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"yahoo":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2019-10":"a #1","2024-01":"n"},"ios":{"2.51.1":"y","4.7.1":"n"},"android":{"2019-10":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y","2025-07":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"yahoo":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported on type selectors.","2":"Not supported. Removes the parenthesis part."}
},
@@ -2062,7 +2094,7 @@
"last_test_date":"2019-10-19",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2019-10":"a #1","2024-01":"n"},"ios":{"2.51.1":"y","4.7.1":"n"},"android":{"2019-10":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"yahoo":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"n"},"outlook-com":{"2019-10":"a #1","2024-01":"n"},"ios":{"2.51.1":"y","4.7.1":"n"},"android":{"2019-10":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y","2025-07":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"yahoo":{"desktop-webmail":{"2019-10":"n #2"},"ios":{"2019-10":"n #2"},"android":{"2019-10":"n #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported on type selectors.","2":"Not supported. Removes the parenthesis part."}
},
@@ -2078,7 +2110,7 @@
"last_test_date":"2019-10-19",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y","2025-07":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported on type selectors."}
},
@@ -2094,7 +2126,7 @@
"last_test_date":"2019-10-19",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y","2025-07":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported on type selectors."}
},
@@ -2110,7 +2142,7 @@
"last_test_date":"2019-10-28",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"n"},"ios":{"13.1":"n"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"n #2"},"ios":{"2019-10":"n"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2019-02":"y","16.80":"a #1 #2"},"outlook-com":{"2019-10":"a #1 #2","2024-01":"a #1 #2"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"thunderbird":{"macos":{"60.8":"y"}},"yahoo":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"}},"aol":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"n"},"android":{"2019-02":"y"}},"samsung-email":{"android":{"6.0.04.6":"y"}},"sfr":{"desktop-webmail":{"2020-01":"y"},"ios":{"2020-01":"n"},"android":{"2020-01":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"n"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"n #2"}},"laposte":{"desktop-webmail":{"2021-08":"n #2"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"n"},"android":{"2022-07":"n"}}},
"stats":{"apple-mail":{"macos":{"12.4":"n"},"ios":{"13.1":"n"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"n #2"},"ios":{"2019-10":"n"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2019-02":"y","16.80":"a #1 #2"},"outlook-com":{"2019-10":"a #1 #2","2024-01":"a #1 #2"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"thunderbird":{"macos":{"60.8":"y"}},"yahoo":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"}},"aol":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"n"},"android":{"2019-02":"y"}},"samsung-email":{"android":{"6.0.04.6":"y"}},"sfr":{"desktop-webmail":{"2020-01":"y","2025-07":"n"},"ios":{"2020-01":"n"},"android":{"2020-01":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"n"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"n #2"}},"laposte":{"desktop-webmail":{"2021-08":"n #2","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"n"},"android":{"2022-07":"n"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported on type selectors.","2":"Buggy. Not filtered but doesn't work."}
},
@@ -2126,7 +2158,7 @@
"last_test_date":"2019-10-28",
"test_url":"https://www.caniemail.com/tests/css-selectors-pseudo-classes.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/cl8ZYgIGE372fkVVuJkwNJDd7B4JUpo23Nz6qANcSlRUA/list",
"stats":{"apple-mail":{"macos":{"12.4":"n"},"ios":{"13.1":"n"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2019-02":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"thunderbird":{"macos":{"60.8":"y"}},"yahoo":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"}},"aol":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"n"},"android":{"2019-02":"y"}},"samsung-email":{"android":{"6.0.04.6":"n"}},"sfr":{"desktop-webmail":{"2020-01":"y"},"ios":{"2020-01":"n"},"android":{"2020-01":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"n"}}},
"stats":{"apple-mail":{"macos":{"12.4":"n"},"ios":{"13.1":"n"}},"gmail":{"desktop-webmail":{"2019-10":"n"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2019-02":"y","16.80":"a #1"},"outlook-com":{"2019-10":"a #1","2024-01":"a #1"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"thunderbird":{"macos":{"60.8":"y"}},"yahoo":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"}},"aol":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"n"},"android":{"2019-02":"y"}},"samsung-email":{"android":{"6.0.04.6":"n"}},"sfr":{"desktop-webmail":{"2020-01":"y","2025-07":"n"},"ios":{"2020-01":"n"},"android":{"2020-01":"n"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"n"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"n"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Only supported on type selectors."}
},
@@ -2142,7 +2174,7 @@
"last_test_date":"2020-05-21",
"test_url":"https://www.caniemail.com/tests/css-pseudo-elements.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/qXO9EwD1KSCSCrmUEccVDxVOl3Cyc4LPAbb83ElW2OFge/list",
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"13":"y"}},"gmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"},"mobile-webmail":{"2020-05":"n"}},"orange":{"desktop-webmail":{"2020-05":"y","2021-03":"n #2","2024-04":"n #2"},"ios":{"2020-05":"y","2024-04":"n"},"android":{"2020-05":"n","2024-04":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-05":"n"},"macos":{"2011":"y","2016":"y","2019":"a #1","16.80":"a #1 #3"},"outlook-com":{"2020-05":"n","2024-01":"a #3"},"ios":{"2.51.1":"y","4.38.0":"n","4.2352.0":"a #3"},"android":{"2020-05":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"thunderbird":{"macos":{"68.8":"y"}},"aol":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"yahoo":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"protonmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"13":"y"}},"gmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"},"mobile-webmail":{"2020-05":"n"}},"orange":{"desktop-webmail":{"2020-05":"y","2021-03":"n #2","2024-04":"n #2"},"ios":{"2020-05":"y","2024-04":"n"},"android":{"2020-05":"n","2024-04":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-05":"n"},"macos":{"2011":"y","2016":"y","2019":"a #1","16.80":"a #1 #3"},"outlook-com":{"2020-05":"n","2024-01":"a #3"},"ios":{"2.51.1":"y","4.38.0":"n","4.2352.0":"a #3"},"android":{"2020-05":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2020-05":"y","2025-07":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"thunderbird":{"macos":{"68.8":"y"}},"aol":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"yahoo":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"protonmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Not supported with non Outlook accounts.","2":"The pseudo-element is supported but the `content` property is not.","3":"Partial. Only supported on type selectors."}
},
@@ -2158,7 +2190,7 @@
"last_test_date":"2020-05-21",
"test_url":"https://www.caniemail.com/tests/css-pseudo-elements.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/qXO9EwD1KSCSCrmUEccVDxVOl3Cyc4LPAbb83ElW2OFge/list",
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"13":"y"}},"gmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"},"mobile-webmail":{"2020-05":"n"}},"orange":{"desktop-webmail":{"2020-05":"y","2021-03":"n #2","2024-04":"n #2"},"ios":{"2020-05":"y","2024-04":"n"},"android":{"2020-05":"n","2024-04":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-05":"n"},"macos":{"2011":"y","2016":"y","2019":"a #1","16.80":"a #1 #3"},"outlook-com":{"2020-05":"n","2024-01":"a #3"},"ios":{"2.51.1":"y","4.38.0":"n","4.2352.0":"a #3"},"android":{"2020-05":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"thunderbird":{"macos":{"68.8":"y"}},"aol":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"yahoo":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"protonmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"13":"y"}},"gmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"},"mobile-webmail":{"2020-05":"n"}},"orange":{"desktop-webmail":{"2020-05":"y","2021-03":"n #2","2024-04":"n #2"},"ios":{"2020-05":"y","2024-04":"n"},"android":{"2020-05":"n","2024-04":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-05":"n"},"macos":{"2011":"y","2016":"y","2019":"a #1","16.80":"a #1 #3"},"outlook-com":{"2020-05":"n","2024-01":"a #3"},"ios":{"2.51.1":"y","4.38.0":"n","4.2352.0":"a #3"},"android":{"2020-05":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2020-05":"y","2025-07":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"thunderbird":{"macos":{"68.8":"y"}},"aol":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"yahoo":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"protonmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Not supported with non Outlook accounts.","2":"The pseudo-element is supported but the `content` property is not.","3":"Partial. Only supported on type selectors."}
},
@@ -2174,7 +2206,7 @@
"last_test_date":"2020-05-21",
"test_url":"https://www.caniemail.com/tests/css-pseudo-elements.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/qXO9EwD1KSCSCrmUEccVDxVOl3Cyc4LPAbb83ElW2OFge/list",
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"13":"y"}},"gmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"},"mobile-webmail":{"2020-05":"n"}},"orange":{"desktop-webmail":{"2020-05":"y","2021-03":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"n"}},"outlook":{"windows":{"2003":"y","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-05":"n"},"macos":{"2011":"y","2016":"y","2019":"a #1","16.80":"a #1 #2"},"outlook-com":{"2020-05":"n","2024-01":"a #2"},"ios":{"2.51.1":"y","4.38.0":"n","4.2352.0":"a #2"},"android":{"2020-05":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"thunderbird":{"macos":{"68.8":"y"}},"aol":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"y"}},"yahoo":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"y"}},"protonmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"13":"y"}},"gmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"},"mobile-webmail":{"2020-05":"n"}},"orange":{"desktop-webmail":{"2020-05":"y","2021-03":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"n"}},"outlook":{"windows":{"2003":"y","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-05":"n"},"macos":{"2011":"y","2016":"y","2019":"a #1","16.80":"a #1 #2"},"outlook-com":{"2020-05":"n","2024-01":"a #2"},"ios":{"2.51.1":"y","4.38.0":"n","4.2352.0":"a #2"},"android":{"2020-05":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2020-05":"y","2025-07":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"thunderbird":{"macos":{"68.8":"y"}},"aol":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"y"}},"yahoo":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"y"}},"protonmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Not supported with non Outlook accounts.","2":"Partial. Only supported on type selectors."}
},
@@ -2190,7 +2222,7 @@
"last_test_date":"2020-05-21",
"test_url":"https://www.caniemail.com/tests/css-pseudo-elements.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/qXO9EwD1KSCSCrmUEccVDxVOl3Cyc4LPAbb83ElW2OFge/list",
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"13":"y"}},"gmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"},"mobile-webmail":{"2020-05":"n"}},"orange":{"desktop-webmail":{"2020-05":"y","2021-03":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"n"}},"outlook":{"windows":{"2003":"y","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-05":"n"},"macos":{"2011":"y","2016":"y","2019":"a #1","16.80":"a #1 #2"},"outlook-com":{"2020-05":"n","2024-01":"a #2"},"ios":{"2.51.1":"y","4.38.0":"n","4.2352.0":"a #2"},"android":{"2020-05":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"thunderbird":{"macos":{"68.8":"y"}},"aol":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"y"}},"yahoo":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"y"}},"protonmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"13":"y"}},"gmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"},"mobile-webmail":{"2020-05":"n"}},"orange":{"desktop-webmail":{"2020-05":"y","2021-03":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"n"}},"outlook":{"windows":{"2003":"y","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-05":"n"},"macos":{"2011":"y","2016":"y","2019":"a #1","16.80":"a #1 #2"},"outlook-com":{"2020-05":"n","2024-01":"a #2"},"ios":{"2.51.1":"y","4.38.0":"n","4.2352.0":"a #2"},"android":{"2020-05":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2020-05":"y","2025-07":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"thunderbird":{"macos":{"68.8":"y"}},"aol":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"y"}},"yahoo":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"y"}},"protonmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"web-de":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"y"},"android":{"2022-07":"y"}}},
"notes":null,
"notes_by_num":{"1":"Not supported with non Outlook accounts.","2":"Partial. Only supported on type selectors."}
},
@@ -2206,7 +2238,7 @@
"last_test_date":"2022-12-28",
"test_url":"https://www.caniemail.com/tests/css-marker.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/7ebtlnke6f0814MElvJWzdRU5lTKcZULpbP9ef9OCuxv3/list",
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"16.2":"y"}},"gmail":{"desktop-webmail":{"2022-12":"n"},"ios":{"2022-12":"n"},"android":{"2022-12":"n"},"mobile-webmail":{"2022-12":"n"}},"orange":{"desktop-webmail":{"2022-12":"y"},"ios":{"2022-12":"y"},"android":{"2022-12":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n #1"},"windows-mail":{"2022-12":"n"},"macos":{"2022-12":"y","16.80":"n"},"outlook-com":{"2022-12":"n","2024-01":"n"},"ios":{"2022-12":"n","2024-01":"n"},"android":{"2022-12":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2022-12":"y"},"ios":{"2022-12":"n"},"android":{"2022-12":"n"}},"thunderbird":{"macos":{"102.6":"y"}},"aol":{"desktop-webmail":{"2022-12":"y"},"ios":{"2022-12":"y"},"android":{"2022-12":"y"}},"yahoo":{"desktop-webmail":{"2022-12":"y"},"ios":{"2022-12":"y"},"android":{"2022-12":"y"}},"protonmail":{"desktop-webmail":{"2022-12":"y"},"ios":{"2022-12":"y"},"android":{"2022-12":"n"}},"hey":{"desktop-webmail":{"2022-12":"y"}},"mail-ru":{"desktop-webmail":{"2022-12":"n"}},"fastmail":{"desktop-webmail":{"2022-12":"y"}},"laposte":{"desktop-webmail":{"2022-12":"y"}}},
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"16.2":"y"}},"gmail":{"desktop-webmail":{"2022-12":"n"},"ios":{"2022-12":"n"},"android":{"2022-12":"n"},"mobile-webmail":{"2022-12":"n"}},"orange":{"desktop-webmail":{"2022-12":"y"},"ios":{"2022-12":"y"},"android":{"2022-12":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n #1"},"windows-mail":{"2022-12":"n"},"macos":{"2022-12":"y","16.80":"n"},"outlook-com":{"2022-12":"n","2024-01":"n"},"ios":{"2022-12":"n","2024-01":"n"},"android":{"2022-12":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2022-12":"y","2025-07":"n"},"ios":{"2022-12":"n"},"android":{"2022-12":"n"}},"thunderbird":{"macos":{"102.6":"y"}},"aol":{"desktop-webmail":{"2022-12":"y"},"ios":{"2022-12":"y"},"android":{"2022-12":"y"}},"yahoo":{"desktop-webmail":{"2022-12":"y"},"ios":{"2022-12":"y"},"android":{"2022-12":"y"}},"protonmail":{"desktop-webmail":{"2022-12":"y"},"ios":{"2022-12":"y"},"android":{"2022-12":"n"}},"hey":{"desktop-webmail":{"2022-12":"y"}},"mail-ru":{"desktop-webmail":{"2022-12":"n"}},"fastmail":{"desktop-webmail":{"2022-12":"y"}},"laposte":{"desktop-webmail":{"2022-12":"y","2025-07":"n"}}},
"notes":null,
"notes_by_num":{"1":"Not supported. But `@list` declarations can achieve the same thing."}
},
@@ -2222,7 +2254,7 @@
"last_test_date":"2020-05-21",
"test_url":"https://www.caniemail.com/tests/css-pseudo-elements.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/qXO9EwD1KSCSCrmUEccVDxVOl3Cyc4LPAbb83ElW2OFge/list",
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"13":"y"}},"gmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"},"mobile-webmail":{"2020-05":"n"}},"orange":{"desktop-webmail":{"2020-05":"n","2021-03":"n #2"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-05":"n"},"macos":{"2011":"y","2016":"y","2019":"a #1","16.80":"a #1 #2"},"outlook-com":{"2020-05":"n","2024-01":"a #2"},"ios":{"2.51.1":"y","4.38.0":"n","4.2352.0":"a #2"},"android":{"2020-05":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"thunderbird":{"macos":{"68.8":"y"}},"aol":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"y"}},"yahoo":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"y"}},"protonmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"hey":{"desktop-webmail":{"2020-06":"n"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"n #2"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"n"},"android":{"2022-07":"n"}}},
"stats":{"apple-mail":{"macos":{"13":"y"},"ios":{"13":"y"}},"gmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"},"mobile-webmail":{"2020-05":"n"}},"orange":{"desktop-webmail":{"2020-05":"n","2021-03":"n #2"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2020-05":"n"},"macos":{"2011":"y","2016":"y","2019":"a #1","16.80":"a #1 #2"},"outlook-com":{"2020-05":"n","2024-01":"a #2"},"ios":{"2.51.1":"y","4.38.0":"n","4.2352.0":"a #2"},"android":{"2020-05":"n"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2020-05":"n","2025-07":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"thunderbird":{"macos":{"68.8":"y"}},"aol":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"y"}},"yahoo":{"desktop-webmail":{"2020-05":"y"},"ios":{"2020-05":"y"},"android":{"2020-05":"y"}},"protonmail":{"desktop-webmail":{"2020-05":"n"},"ios":{"2020-05":"n"},"android":{"2020-05":"n"}},"hey":{"desktop-webmail":{"2020-06":"n"}},"mail-ru":{"desktop-webmail":{"2020-10":"n"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"n #2","2025-07":"n"}},"gmx":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"web-de":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-07":"n"},"android":{"2022-07":"n"}}},
"notes":null,
"notes_by_num":{"1":"Not supported with non Outlook accounts.","2":"The pseudo-element is supported but `<input>` elements are not.","3":"Partial. Only supported on type selectors."}
},
@@ -2350,7 +2382,7 @@
"last_test_date":"2019-10-13",
"test_url":"https://www.caniemail.com/tests/css-selectors.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/kQbnzGXMSxMg2NDGmrcxIXOHrROwokTB29RcSssnkoPlS/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"n","2024-04":"y"},"ios":{"2019-10":"y","2024-04":"y"},"android":{"2019-10":"y","2024-04":"y"}},"outlook":{"windows":{"2003":"y","2007":"n #3","2010":"n #3","2013":"n #3","2016":"n #3","2019":"n #3"},"windows-mail":{"2019-10":"n #3"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"n #4","2024-01":"n #4"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"a #5"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"a #5"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"n","2024-04":"y"},"ios":{"2019-10":"y","2024-04":"y"},"android":{"2019-10":"y","2024-04":"y"}},"outlook":{"windows":{"2003":"y","2007":"n #3","2010":"n #3","2013":"n #3","2016":"n #3","2019":"n #3"},"windows-mail":{"2019-10":"n #3"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"n #4","2024-01":"n #4"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2","2025-06":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"a #5"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"a #5"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Not supported with non Google accounts.","2":"Buggy. The first `<head>` in the HTML is removed, so `<style>` elements need to be in a second `<head>` element.","3":"Buggy. Styles will be applied to the first selector of the chain.","4":"Buggy. Only the first selector of the chain is prefixed in the styles, but all classes are prefixed in the HTML.","5":"Partial. Only when used as class or ID selectors"}
},
@@ -2366,7 +2398,7 @@
"last_test_date":"2019-10-13",
"test_url":"https://www.caniemail.com/tests/css-selectors.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/kQbnzGXMSxMg2NDGmrcxIXOHrROwokTB29RcSssnkoPlS/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"n"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2023-06":"n"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"y","2024-01":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"n"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2023-06":"n"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"y","2024-01":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2","2025-06":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Not supported with non Google accounts.","2":"Buggy. The first `<head>` in the HTML is removed, so `<style>` elements need to be in a second `<head>` element."}
},
@@ -2382,7 +2414,7 @@
"last_test_date":"2019-10-13",
"test_url":"https://www.caniemail.com/tests/css-selectors.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/kQbnzGXMSxMg2NDGmrcxIXOHrROwokTB29RcSssnkoPlS/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"y","2010":"y","2013":"y","2016":"y","2019":"y"},"windows-mail":{"2019-10":"y"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"y","2024-01":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"y","2010":"y","2013":"y","2016":"y","2019":"y"},"windows-mail":{"2019-10":"y"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"y","2024-01":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2","2025-06":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Not supported with non Google accounts.","2":"Buggy. The first `<head>` in the HTML is removed, so `<style>` elements need to be in a second `<head>` element."}
},
@@ -2398,7 +2430,7 @@
"last_test_date":"2019-10-13",
"test_url":"https://www.caniemail.com/tests/css-selectors.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/kQbnzGXMSxMg2NDGmrcxIXOHrROwokTB29RcSssnkoPlS/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"y","2010":"y","2013":"y","2016":"y","2019":"y"},"windows-mail":{"2019-10":"y"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"y","2024-01":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"a #3"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"a #3"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"y","2010":"y","2013":"y","2016":"y","2019":"y"},"windows-mail":{"2019-10":"y"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"y","2024-01":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2","2025-06":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"a #3"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"a #3"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Not supported with non Google accounts.","2":"Buggy. The first `<head>` in the HTML is removed, so `<style>` elements need to be in a second `<head>` element.","3":"Partial. Only when used as class or ID selectors"}
},
@@ -2430,7 +2462,7 @@
"last_test_date":"2019-10-13",
"test_url":"https://www.caniemail.com/tests/css-selectors.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/kQbnzGXMSxMg2NDGmrcxIXOHrROwokTB29RcSssnkoPlS/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"y","2010":"y","2013":"y","2016":"y","2019":"y"},"windows-mail":{"2019-10":"y"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"y","2024-01":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"a #3"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"a #3"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"y","2010":"y","2013":"y","2016":"y","2019":"y"},"windows-mail":{"2019-10":"y"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"y","2024-01":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2","2025-06":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"a #3"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"a #3"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Not supported with non Google accounts.","2":"Buggy. The first `<head>` in the HTML is removed, so `<style>` elements need to be in a second `<head>` element.","3":"Partial. Only when used as class or ID selectors"}
},
@@ -2446,7 +2478,7 @@
"last_test_date":"2019-10-13",
"test_url":"https://www.caniemail.com/tests/css-selectors.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/kQbnzGXMSxMg2NDGmrcxIXOHrROwokTB29RcSssnkoPlS/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"y","2010":"y","2013":"y","2016":"y","2019":"y"},"windows-mail":{"2019-10":"y"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"y","2024-01":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"n"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"y","2010":"y","2013":"y","2016":"y","2019":"y"},"windows-mail":{"2019-10":"y"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"y","2024-01":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2","2025-06":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"n"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Not supported with non Google accounts.","2":"Buggy. The first `<head>` in the HTML is removed, so `<style>` elements need to be in a second `<head>` element."}
},
@@ -2462,7 +2494,7 @@
"last_test_date":"2019-10-13",
"test_url":"https://www.caniemail.com/tests/css-selectors.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/kQbnzGXMSxMg2NDGmrcxIXOHrROwokTB29RcSssnkoPlS/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"y","2010":"y","2013":"y","2016":"y","2019":"y"},"windows-mail":{"2019-10":"y"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"y","2024-01":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"y","2010":"y","2013":"y","2016":"y","2019":"y"},"windows-mail":{"2019-10":"y"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"y","2024-01":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2","2025-06":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"n"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Not supported with non Google accounts.","2":"Buggy. The first `<head>` in the HTML is removed, so `<style>` elements need to be in a second `<head>` element."}
},
@@ -2478,7 +2510,7 @@
"last_test_date":"2019-10-13",
"test_url":"https://www.caniemail.com/tests/css-selectors.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/kQbnzGXMSxMg2NDGmrcxIXOHrROwokTB29RcSssnkoPlS/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"y","2024-01":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n #3"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"13.1":"y"}},"gmail":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"a #1"},"android":{"2019-10":"a #1"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-10":"y","2021-03":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"outlook":{"windows":{"2003":"y","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-10":"n"},"macos":{"2011":"y","2016":"y","16.80":"y"},"outlook-com":{"2019-10":"y","2024-01":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"samsung-email":{"android":{"6.0":"y"}},"sfr":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"n"},"android":{"2019-10":"n"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"y"}},"yahoo":{"desktop-webmail":{"2019-10":"y"},"ios":{"2019-10":"y"},"android":{"2019-10":"a #2","2025-06":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n"},"ios":{"2020-03":"n"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"n #3"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"web-de":{"desktop-webmail":{"2022-06":"y"},"ios":{"2022-06":"y"},"android":{"2022-06":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-06":"y"},"android":{"2022-06":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Not supported with non Google accounts.","2":"Buggy. The first `<head>` in the HTML is removed, so `<style>` elements need to be in a second `<head>` element.","3":"Not supported. The selector is removed and left prefixed with the outer most parent element."}
},
@@ -2542,7 +2574,7 @@
"last_test_date":"2022-07-21",
"test_url":"https://www.caniemail.com/tests/css-tab-size.html",
"test_results_url":"https://testi.at/proj/Rk9H1m9ubAYH1DwUqZu8G",
"stats":{"apple-mail":{"macos":{"16":"y","17":"y","18":"y","19":"y","20":"y","21":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"u"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2022-07":"y","16.80":"y #2"},"outlook-com":{"2022-07":"y #2","2024-01":"y #2"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"samsung-email":{"android":{"2022-07":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"protonmail":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"n #1"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"n"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"n"}}},
"stats":{"apple-mail":{"macos":{"16":"y","17":"y","18":"y","19":"y","20":"y","21":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"u"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2022-07":"y","16.80":"y #2"},"outlook-com":{"2022-07":"y #2","2024-01":"y #2"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"samsung-email":{"android":{"2022-07":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"n #1"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"n"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"n"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"n"}}},
"notes":null,
"notes_by_num":{"1":"Supports `tab-size` but doesn't support `white-space`. Therefore, `tab-size` is not effectively visible","2":"Supports `tab-size` but strips the tab character `&#0009;`"}
},
@@ -2558,7 +2590,7 @@
"last_test_date":"2022-07-20",
"test_url":"https://www.caniemail.com/tests/css-table-layout.html",
"test_results_url":"https://testi.at/proj/G4buV6sBBxUr6quykrtVA3sk",
"stats":{"apple-mail":{"macos":{"16":"y","17":"y","18":"y","19":"y","20":"y","21":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"},"mobile-webmail":{"2022-07":"u"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2022-07":"y","16.80":"n #1"},"outlook-com":{"2022-07":"y","2024-01":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"yahoo":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"aol":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"samsung-email":{"android":{"2022-07":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"protonmail":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}}},
"stats":{"apple-mail":{"macos":{"16":"y","17":"y","18":"y","19":"y","20":"y","21":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"},"mobile-webmail":{"2022-07":"u"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2022-07":"y","16.80":"n #1"},"outlook-com":{"2022-07":"y","2024-01":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"yahoo":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"aol":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"samsung-email":{"android":{"2022-07":"y"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}}},
"notes":null,
"notes_by_num":{"1":"Not supported. All tables are forced to `table-layout:fixed`."}
},
@@ -2569,12 +2601,12 @@
"description":"The `text-align-last` CSS property sets how the last line of a block or a line right before a forced line break is aligned.",
"url":"https://www.caniemail.com/features/css-text-align-last/",
"category":"css",
"tags":[],
"tags":["i18n"],
"keywords":"align, align-last",
"last_test_date":"2022-08-31",
"test_url":"https://www.caniemail.com/tests/css-text-align-last.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/LxplTmJT9Ilq9GUyn8Aq8MVK6EO427qmx1Ic4A7jc7bOJ/list",
"stats":{"apple-mail":{"macos":{"2022-10":"y"},"ios":{"11":"n","12":"n","13":"n","14":"n","15":"n","16.0":"y"}},"gmail":{"desktop-webmail":{"2022-08":"y"},"ios":{"2022-08":"y"},"android":{"2022-08":"y"},"mobile-webmail":{"2021-08":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"macos":{"2022-08":"n","16.80":"n"},"outlook-com":{"2022-08":"y","2024-01":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"}},"yahoo":{"desktop-webmail":{"2022-08":"n","2024-03":"n"},"ios":{"2024-03":"n"},"android":{"2024-03":"n"}},"aol":{"desktop-webmail":{"2022-08":"n"}},"samsung-email":{"android":{"6.1.51.1":"y"}},"free-fr":{"desktop-webmail":{"2022-08":"y"}},"t-online-de":{"desktop-webmail":{"2022-08":"y"}},"mail-ru":{"desktop-webmail":{"2022-08":"y"}}},
"stats":{"apple-mail":{"macos":{"2022-10":"y"},"ios":{"11":"n","12":"n","13":"n","14":"n","15":"n","16.0":"y"}},"gmail":{"desktop-webmail":{"2022-08":"y"},"ios":{"2022-08":"y"},"android":{"2022-08":"y"},"mobile-webmail":{"2021-08":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"macos":{"2022-08":"n","16.80":"n"},"outlook-com":{"2022-08":"y","2024-01":"n"},"ios":{"2022-08":"n"},"android":{"2022-08":"n"}},"yahoo":{"desktop-webmail":{"2022-08":"n","2024-03":"n"},"ios":{"2024-03":"n"},"android":{"2024-03":"n"}},"aol":{"desktop-webmail":{"2022-08":"n"}},"samsung-email":{"android":{"6.1.51.1":"y"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"free-fr":{"desktop-webmail":{"2022-08":"y"}},"t-online-de":{"desktop-webmail":{"2022-08":"y"}},"mail-ru":{"desktop-webmail":{"2022-08":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -2585,7 +2617,7 @@
"description":"Sets the horizontal alignment of the content.",
"url":"https://www.caniemail.com/features/css-text-align/",
"category":"css",
"tags":[],
"tags":["i18n"],
"keywords":"align",
"last_test_date":"2021-09-24",
"test_url":"https://www.caniemail.com/tests/css-text-align.html",
@@ -2622,7 +2654,7 @@
"last_test_date":"2023-12-06",
"test_url":"https://www.caniemail.com/tests/css-text-decoration-line.html",
"test_results_url":"https://testi.at/proj/kg6y1a4eiynkf8z7t4",
"stats":{"apple-mail":{"macos":{"2023-12":"y"},"ios":{"11":"n","12":"y","13":"y","14":"y"}},"gmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"6":"n","7":"n","8":"y","9":"y","10":"y","11":"y","12":"y","13":"y"},"mobile-webmail":{"2023-12":"y"}},"orange":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2023-12":"n"},"macos":{"2023-12":"y","16.80":"y"},"outlook-com":{"2023-12":"y","2024-01":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"yahoo":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"n"}},"aol":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"n"}},"samsung-email":{"android":{"2023-12":"y"}},"sfr":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"thunderbird":{"macos":{"2023-12":"y"}},"protonmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"hey":{"desktop-webmail":{"2023-12":"u"}},"mail-ru":{"desktop-webmail":{"2023-12":"y"}},"fastmail":{"desktop-webmail":{"2023-12":"u"}},"laposte":{"desktop-webmail":{"2023-12":"u"}},"gmx":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"web-de":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2023-12":"u"},"android":{"2023-12":"u"}}},
"stats":{"apple-mail":{"macos":{"2023-12":"y"},"ios":{"11":"n","12":"y","13":"y","14":"y"}},"gmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"6":"n","7":"n","8":"y","9":"y","10":"y","11":"y","12":"y","13":"y"},"mobile-webmail":{"2023-12":"y"}},"orange":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2023-12":"n"},"macos":{"2023-12":"y","16.80":"y"},"outlook-com":{"2023-12":"y","2024-01":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"yahoo":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"n","2025-06":"y"}},"aol":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"n"}},"samsung-email":{"android":{"2023-12":"y"}},"sfr":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"thunderbird":{"macos":{"2023-12":"y"}},"protonmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"hey":{"desktop-webmail":{"2023-12":"u"}},"mail-ru":{"desktop-webmail":{"2023-12":"y"}},"fastmail":{"desktop-webmail":{"2023-12":"u"}},"laposte":{"desktop-webmail":{"2023-12":"u"}},"gmx":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"web-de":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2023-12":"u"},"android":{"2023-12":"u"}}},
"notes":null,
"notes_by_num":null
},
@@ -2638,7 +2670,7 @@
"last_test_date":"2023-12-08",
"test_url":"https://www.caniemail.com/tests/css-text-decoration-skip-ink.html",
"test_results_url":"https://testi.at/proj/n477u94ixnz0kbrh6",
"stats":{"apple-mail":{"macos":{"10.15":"n","11.7":"n","12.7":"y","13.6":"y"},"ios":{"10":"n","11":"n","12":"n","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"},"mobile-webmail":{"2023-12":"n"}},"orange":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2023-12":"n"},"macos":{"2023-12":"n","16.80":"n"},"outlook-com":{"2023-12":"n","2024-01":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"}},"yahoo":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"}},"aol":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"}},"samsung-email":{"android":{"2023-12":"y"}},"sfr":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"thunderbird":{"macos":{"2023-12":"y"}},"protonmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"u"}},"hey":{"desktop-webmail":{"2023-12":"y"}},"mail-ru":{"desktop-webmail":{"2023-12":"y"}},"fastmail":{"desktop-webmail":{"2023-12":"y"}},"laposte":{"desktop-webmail":{"2023-12":"y"}},"gmx":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"web-de":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2023-12":"u"},"android":{"2023-12":"u"}}},
"stats":{"apple-mail":{"macos":{"10.15":"n","11.7":"n","12.7":"y","13.6":"y"},"ios":{"10":"n","11":"n","12":"n","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"},"mobile-webmail":{"2023-12":"n"}},"orange":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2023-12":"n"},"macos":{"2023-12":"n","16.80":"n"},"outlook-com":{"2023-12":"n","2024-01":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"}},"yahoo":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"}},"aol":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"}},"samsung-email":{"android":{"2023-12":"y"}},"sfr":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"thunderbird":{"macos":{"2023-12":"y"}},"protonmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"hey":{"desktop-webmail":{"2023-12":"y"}},"mail-ru":{"desktop-webmail":{"2023-12":"y"}},"fastmail":{"desktop-webmail":{"2023-12":"y"}},"laposte":{"desktop-webmail":{"2023-12":"y"}},"gmx":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"web-de":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2023-12":"u"},"android":{"2023-12":"u"}}},
"notes":null,
"notes_by_num":null
},
@@ -2654,7 +2686,7 @@
"last_test_date":"2023-12-06",
"test_url":"https://www.caniemail.com/tests/css-text-decoration-style.html",
"test_results_url":"https://testi.at/proj/jalr04oy0yrxfd7kuo",
"stats":{"apple-mail":{"macos":{"2023-12":"y"},"ios":{"11":"n","12":"y","13":"y","14":"y"}},"gmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"6":"n","7":"n","8":"y","9":"y","10":"y","11":"y","12":"y","13":"y"},"mobile-webmail":{"2023-12":"y"}},"orange":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2023-12":"n"},"macos":{"2023-12":"y","16.80":"y"},"outlook-com":{"2023-12":"y","2024-01":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"yahoo":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"n"}},"aol":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"n"}},"samsung-email":{"android":{"2023-12":"y"}},"sfr":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"thunderbird":{"macos":{"2023-12":"y"}},"protonmail":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"hey":{"desktop-webmail":{"2023-12":"u"}},"mail-ru":{"desktop-webmail":{"2023-12":"y"}},"fastmail":{"desktop-webmail":{"2023-12":"u"}},"laposte":{"desktop-webmail":{"2023-12":"u"}},"gmx":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"web-de":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2023-12":"u"},"android":{"2023-12":"u"}}},
"stats":{"apple-mail":{"macos":{"2023-12":"y"},"ios":{"11":"n","12":"y","13":"y","14":"y"}},"gmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"6":"n","7":"n","8":"y","9":"y","10":"y","11":"y","12":"y","13":"y"},"mobile-webmail":{"2023-12":"y"}},"orange":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2023-12":"n"},"macos":{"2023-12":"y","16.80":"y"},"outlook-com":{"2023-12":"y","2024-01":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"yahoo":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"n","2025-06":"y"}},"aol":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"n"}},"samsung-email":{"android":{"2023-12":"y"}},"sfr":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"thunderbird":{"macos":{"2023-12":"y"}},"protonmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"hey":{"desktop-webmail":{"2023-12":"u"}},"mail-ru":{"desktop-webmail":{"2023-12":"y"}},"fastmail":{"desktop-webmail":{"2023-12":"u"}},"laposte":{"desktop-webmail":{"2023-12":"u"}},"gmx":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"web-de":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2023-12":"u"},"android":{"2023-12":"u"}}},
"notes":null,
"notes_by_num":null
},
@@ -2681,7 +2713,7 @@
"description":"Tested with the values `overline`, `underline` and `line-through`.",
"url":"https://www.caniemail.com/features/css-text-decoration/",
"category":"css",
"tags":[],
"tags":["i18n"],
"keywords":"underline",
"last_test_date":"2019-02-28",
"test_url":"https://www.caniemail.com/tests/css-text-decoration.html",
@@ -2702,7 +2734,7 @@
"last_test_date":"2022-07-07",
"test_url":"https://www.caniemail.com/tests/css-text-emphasis.html",
"test_results_url":"https://testi.at/proj/O0yCP6t6l3sZ1xFrLZuEx6I5O",
"stats":{"apple-mail":{"macos":{"2022-07":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2022-07":"y","16.80":"y"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"n","11":"n"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"78.14":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"stats":{"apple-mail":{"macos":{"2022-07":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2022-07":"y","16.80":"y"},"outlook-com":{"2022-07":"n","2024-01":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"n","11":"n"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"78.14":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -2718,7 +2750,7 @@
"last_test_date":"2022-07-07",
"test_url":"https://www.caniemail.com/tests/css-text-emphasis.html",
"test_results_url":"https://testi.at/proj/O0yCP6t6l3sZ1xFrLZuEx6I5O",
"stats":{"apple-mail":{"macos":{"2022-07":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2022-07":"y","16.80":"y"},"outlook-com":{"2022-07":"y","2024-01":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"n","11":"n"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"78.14":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"stats":{"apple-mail":{"macos":{"2022-07":"y"},"ios":{"11":"y","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"},"mobile-webmail":{"2022-07":"n"}},"orange":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2022-07":"n"},"macos":{"2022-07":"y","16.80":"y"},"outlook-com":{"2022-07":"y","2024-01":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"n"}},"samsung-email":{"android":{"10":"n","11":"n"}},"sfr":{"desktop-webmail":{"2022-07":"u"},"ios":{"2022-07":"u"},"android":{"2022-07":"u"}},"thunderbird":{"macos":{"78.14":"u"}},"aol":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"yahoo":{"desktop-webmail":{"2022-07":"n"},"ios":{"2022-07":"n"},"android":{"2022-07":"n"}},"protonmail":{"desktop-webmail":{"2022-07":"y"},"ios":{"2022-07":"y"},"android":{"2022-07":"y"}},"hey":{"desktop-webmail":{"2022-07":"u"}},"mail-ru":{"desktop-webmail":{"2022-07":"y"}},"fastmail":{"desktop-webmail":{"2022-07":"u"}},"laposte":{"desktop-webmail":{"2022-07":"u"}},"gmx":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"n"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -2766,7 +2798,7 @@
"last_test_date":"2023-12-08",
"test_url":"https://www.caniemail.com/tests/css-text-orientation.html",
"test_results_url":"https://testi.at/proj/6vppidbfjxnczrxh4",
"stats":{"apple-mail":{"macos":{"10.15":"a #1","11.7":"y","12.7":"y","13.6":"y","14.1":"y"},"ios":{"10":"n","11":"n","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"10":"n","11":"n","12":"y","13":"y","14":"y","15":"y"},"android":{"2023-12":"y"},"mobile-webmail":{"2023-12":"y"}},"orange":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2023-12":"n"},"macos":{"2023-12":"n","16.80":"y"},"outlook-com":{"2023-12":"y","2024-01":"y"},"ios":{"10":"n","11":"n","12":"y","13":"y","14":"y","15":"y"},"android":{"2023-12":"y"}},"yahoo":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"}},"aol":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"}},"samsung-email":{"android":{"2023-12":"y"}},"sfr":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"thunderbird":{"macos":{"2023-12":"y"}},"protonmail":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"hey":{"desktop-webmail":{"2023-12":"u"}},"mail-ru":{"desktop-webmail":{"2023-12":"y"}},"fastmail":{"desktop-webmail":{"2023-12":"u"}},"laposte":{"desktop-webmail":{"2023-12":"u"}},"gmx":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"web-de":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2023-12":"u"},"android":{"2023-12":"u"}}},
"stats":{"apple-mail":{"macos":{"10.15":"a #1","11.7":"y","12.7":"y","13.6":"y","14.1":"y"},"ios":{"10":"n","11":"n","12":"y","13":"y","14":"y","15":"y"}},"gmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"10":"n","11":"n","12":"y","13":"y","14":"y","15":"y"},"android":{"2023-12":"y"},"mobile-webmail":{"2023-12":"y"}},"orange":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2023-12":"n"},"macos":{"2023-12":"n","16.80":"y"},"outlook-com":{"2023-12":"y","2024-01":"y"},"ios":{"10":"n","11":"n","12":"y","13":"y","14":"y","15":"y"},"android":{"2023-12":"y"}},"yahoo":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"}},"aol":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"}},"samsung-email":{"android":{"2023-12":"y"}},"sfr":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"thunderbird":{"macos":{"2023-12":"y"}},"protonmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"hey":{"desktop-webmail":{"2023-12":"u"}},"mail-ru":{"desktop-webmail":{"2023-12":"y"}},"fastmail":{"desktop-webmail":{"2023-12":"u"}},"laposte":{"desktop-webmail":{"2023-12":"u"}},"gmx":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"web-de":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2023-12":"u"},"android":{"2023-12":"u"}}},
"notes":null,
"notes_by_num":{"1":"Partial. `sideways` is not supported"}
},
@@ -2798,7 +2830,7 @@
"last_test_date":"2019-02-28",
"test_url":"https://www.caniemail.com/tests/css-box-model.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/pyPQFHSYLFrhbRShalju0B2fYNwUgLuyKTLx4MLqiw5mE/list",
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"12.1":"y"}},"gmail":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-08":"y","2021-03":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-02":"n"},"macos":{"2019-02":"y","16.80":"n"},"outlook-com":{"2019-02":"n","2024-01":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"}},"yahoo":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"n"}},"aol":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"}},"samsung-email":{"android":{"5.0.10.2":"y"}},"sfr":{"desktop-webmail":{"2020-01":"y"},"ios":{"2020-01":"y"},"android":{"2020-01":"y"}},"thunderbird":{"macos":{"60.5":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"y"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-08":"y"},"ios":{"2022-08":"y"},"android":{"2022-08":"y"}},"web-de":{"desktop-webmail":{"2022-08":"y"},"ios":{"2022-08":"y"},"android":{"2022-08":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-08":"y"},"android":{"2022-08":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y"},"ios":{"12.1":"y"}},"gmail":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-08":"y","2021-03":"y"},"ios":{"2019-08":"y"},"android":{"2019-08":"y"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-02":"n"},"macos":{"2019-02":"y","16.80":"n"},"outlook-com":{"2019-02":"n","2024-01":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"}},"yahoo":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"n","2025-06":"y"}},"aol":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y"},"android":{"2019-02":"y"}},"samsung-email":{"android":{"5.0.10.2":"y"}},"sfr":{"desktop-webmail":{"2020-01":"y"},"ios":{"2020-01":"y"},"android":{"2020-01":"y"}},"thunderbird":{"macos":{"60.5":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"y"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-08":"y"},"ios":{"2022-08":"y"},"android":{"2022-08":"y"}},"web-de":{"desktop-webmail":{"2022-08":"y"},"ios":{"2022-08":"y"},"android":{"2022-08":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-08":"y"},"android":{"2022-08":"y"}}},
"notes":null,
"notes_by_num":null
},
@@ -2809,7 +2841,7 @@
"description":"Each of the six `text-transform` values defined by MDN (`capitalize`, `uppercase`, `lowercase`, `none`, `full-width`, `full-size-kana`).",
"url":"https://www.caniemail.com/features/css-text-transform/",
"category":"css",
"tags":[],
"tags":["i18n"],
"keywords":null,
"last_test_date":"2021-09-19",
"test_url":"https://www.caniemail.com/tests/css-text-transform.html",
@@ -2846,7 +2878,7 @@
"last_test_date":"2023-12-08",
"test_url":"https://www.caniemail.com/tests/css-text-underline-position.html",
"test_results_url":"https://testi.at/proj/yd99u8e12nvh97jcv",
"stats":{"apple-mail":{"macos":{"2023-12":"a #1"},"ios":{"2023-12":"a #1"}},"gmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"a #1"},"android":{"2023-12":"y"},"mobile-webmail":{"2023-12":"y"}},"orange":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2023-12":"n"},"macos":{"2023-12":"n","16.80":"n"},"outlook-com":{"2023-12":"y","2024-01":"y"},"ios":{"2023-12":"a #1"},"android":{"2023-12":"y"}},"yahoo":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"}},"aol":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"}},"samsung-email":{"android":{"2023-12":"y"}},"sfr":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"thunderbird":{"macos":{"2023-12":"y"}},"protonmail":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"hey":{"desktop-webmail":{"2023-12":"u"}},"mail-ru":{"desktop-webmail":{"2023-12":"y"}},"fastmail":{"desktop-webmail":{"2023-12":"u"}},"laposte":{"desktop-webmail":{"2023-12":"u"}},"gmx":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"web-de":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2023-12":"u"},"android":{"2023-12":"u"}}},
"stats":{"apple-mail":{"macos":{"2023-12":"a #1"},"ios":{"2023-12":"a #1"}},"gmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"a #1"},"android":{"2023-12":"y"},"mobile-webmail":{"2023-12":"y"}},"orange":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2023-12":"n"},"macos":{"2023-12":"n","16.80":"n"},"outlook-com":{"2023-12":"y","2024-01":"y"},"ios":{"2023-12":"a #1"},"android":{"2023-12":"y"}},"yahoo":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"}},"aol":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"n"},"android":{"2023-12":"n"}},"samsung-email":{"android":{"2023-12":"y"}},"sfr":{"desktop-webmail":{"2023-12":"u"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"thunderbird":{"macos":{"2023-12":"y"}},"protonmail":{"desktop-webmail":{"2023-12":"y"},"ios":{"2023-12":"y"},"android":{"2023-12":"y"}},"hey":{"desktop-webmail":{"2023-12":"u"}},"mail-ru":{"desktop-webmail":{"2023-12":"y"}},"fastmail":{"desktop-webmail":{"2023-12":"u"}},"laposte":{"desktop-webmail":{"2023-12":"u"}},"gmx":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"web-de":{"desktop-webmail":{"2023-12":"n"},"ios":{"2023-12":"u"},"android":{"2023-12":"u"}},"ionos-1and1":{"desktop-webmail":{"2023-12":"u"},"android":{"2023-12":"u"}}},
"notes":null,
"notes_by_num":{"1":"Partial. Supports `under` but not `right` and `left`"}
},
@@ -3182,9 +3214,9 @@
"last_test_date":"2024-02-14",
"test_url":"https://www.caniemail.com/tests/css-user-select.html",
"test_results_url":"https://testi.at/proj/9zjptajgcxyzc74ockp",
"stats":{"apple-mail":{"macos":{"2024-02":"y #1"},"ios":{"2024-02":"a #1 #2"}},"gmail":{"desktop-webmail":{"2024-02":"n #3"},"ios":{"2024-02":"n #3"},"android":{"2024-02":"n"},"mobile-webmail":{"2024-02":"u"}},"orange":{"desktop-webmail":{"2024-02":"u"},"ios":{"2024-02":"u"},"android":{"2024-02":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-02":"n"},"macos":{"2024-02":"n #3"},"outlook-com":{"2024-02":"n #3"},"ios":{"2024-02":"n #3"},"android":{"2024-02":"n"}},"yahoo":{"desktop-webmail":{"2024-02":"n #3"},"ios":{"2024-02":"n"},"android":{"2024-02":"n"}},"aol":{"desktop-webmail":{"2024-02":"n #3"},"ios":{"2024-02":"n"},"android":{"2024-02":"n"}},"samsung-email":{"android":{"2024-02":"y"}},"sfr":{"desktop-webmail":{"2024-02":"u"},"ios":{"2024-02":"u"},"android":{"2024-02":"u"}},"thunderbird":{"macos":{"2024-02":"u"}},"protonmail":{"desktop-webmail":{"2024-02":"u"},"ios":{"2024-02":"u"},"android":{"2024-02":"u"}},"hey":{"desktop-webmail":{"2024-02":"u"}},"mail-ru":{"desktop-webmail":{"2024-02":"y"}},"fastmail":{"desktop-webmail":{"2024-02":"u"}},"laposte":{"desktop-webmail":{"2024-02":"u"}},"gmx":{"desktop-webmail":{"2024-02":"n #3"},"ios":{"2024-02":"u"},"android":{"2024-02":"u"}},"web-de":{"desktop-webmail":{"2024-02":"n #3"},"ios":{"2024-02":"n"},"android":{"2024-02":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-02":"u"},"android":{"2024-02":"u"}}},
"stats":{"apple-mail":{"macos":{"2024-02":"y #1"},"ios":{"2024-02":"a #1 #2"}},"gmail":{"desktop-webmail":{"2024-02":"n #3"},"ios":{"2024-02":"n #3"},"android":{"2024-02":"n"},"mobile-webmail":{"2024-02":"u"}},"orange":{"desktop-webmail":{"2024-02":"u"},"ios":{"2024-02":"u"},"android":{"2024-02":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-02":"n"},"macos":{"2024-02":"n #3"},"outlook-com":{"2024-02":"n #3"},"ios":{"2024-02":"n #3"},"android":{"2024-02":"n"}},"yahoo":{"desktop-webmail":{"2024-02":"n #3"},"ios":{"2024-02":"n"},"android":{"2024-02":"n"}},"aol":{"desktop-webmail":{"2024-02":"n #3"},"ios":{"2024-02":"n"},"android":{"2024-02":"n"}},"samsung-email":{"android":{"2024-02":"y"}},"sfr":{"desktop-webmail":{"2024-02":"u"},"ios":{"2024-02":"u"},"android":{"2024-02":"u"}},"thunderbird":{"macos":{"2024-02":"u"}},"protonmail":{"desktop-webmail":{"2024-02":"a #2 #4"},"ios":{"2024-02":"a #2 #4"},"android":{"2024-02":"a #2 #4"}},"hey":{"desktop-webmail":{"2024-02":"u"}},"mail-ru":{"desktop-webmail":{"2024-02":"y"}},"fastmail":{"desktop-webmail":{"2024-02":"u"}},"laposte":{"desktop-webmail":{"2024-02":"u"}},"gmx":{"desktop-webmail":{"2024-02":"n #3"},"ios":{"2024-02":"u"},"android":{"2024-02":"u"}},"web-de":{"desktop-webmail":{"2024-02":"n #3"},"ios":{"2024-02":"n"},"android":{"2024-02":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-02":"u"},"android":{"2024-02":"u"}}},
"notes":null,
"notes_by_num":{"1":"Works with `-webkit` prefix","2":"`all` value does not work","3":"Property is stripped from style tag"}
"notes_by_num":{"1":"Works with `-webkit` prefix","2":"`all` value does not work","3":"Property is stripped from style tag","4":"`none` value does not work, client allow to select text anyway"}
},
{
@@ -3230,7 +3262,7 @@
"last_test_date":"2019-02-28",
"test_url":"https://www.caniemail.com/tests/css-visual-effects.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/DhTRmGsVH6uobU4pHD3CasJywfBL4HnEjA1LOF8f9ctso/list",
"stats":{"apple-mail":{"macos":{"12.4":"y #1"},"ios":{"12.1":"y #1"}},"gmail":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-08":"y","2021-03":"a #2","2024-04":"n"},"ios":{"2019-08":"a #1","2024-04":"n"},"android":{"2019-08":"y","2024-04":"n"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-02":"n"},"macos":{"2019-02":"y #1","16.80":"y #1"},"outlook-com":{"2019-02":"y","2024-01":"y"},"ios":{"2019-02":"y #1"},"android":{"2019-02":"y"}},"thunderbird":{"macos":{"60.8":"y"}},"yahoo":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y #1"},"android":{"2019-02":"n"}},"aol":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"y #1"},"android":{"2019-02":"y"}},"samsung-email":{"android":{"5.0.10.2":"y"}},"sfr":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"y #1"},"android":{"2019-08":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"y #1"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-09":"y"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"y"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"stats":{"apple-mail":{"macos":{"12.4":"y #1"},"ios":{"12.1":"y #1"}},"gmail":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"n"},"android":{"2019-02":"n"},"mobile-webmail":{"2020-02":"n"}},"orange":{"desktop-webmail":{"2019-08":"y","2021-03":"a #2","2024-04":"n"},"ios":{"2019-08":"a #1","2024-04":"n"},"android":{"2019-08":"y","2024-04":"n"}},"outlook":{"windows":{"2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2019-02":"n"},"macos":{"2019-02":"y #1","16.80":"y #1"},"outlook-com":{"2019-02":"y","2024-01":"y"},"ios":{"2019-02":"y #1"},"android":{"2019-02":"y"}},"thunderbird":{"macos":{"60.8":"y"}},"yahoo":{"desktop-webmail":{"2019-02":"y"},"ios":{"2019-02":"y #1"},"android":{"2019-02":"n","2025-06":"y"}},"aol":{"desktop-webmail":{"2019-02":"n"},"ios":{"2019-02":"y #1"},"android":{"2019-02":"y"}},"samsung-email":{"android":{"5.0.10.2":"y"}},"sfr":{"desktop-webmail":{"2019-08":"y"},"ios":{"2019-08":"y #1"},"android":{"2019-08":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"y"},"ios":{"2020-03":"y #1"},"android":{"2020-03":"y"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-10":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"}},"gmx":{"desktop-webmail":{"2022-09":"y"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"web-de":{"desktop-webmail":{"2022-09":"y"},"ios":{"2022-09":"y"},"android":{"2022-09":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-09":"y"},"android":{"2022-09":"y"}}},
"notes":null,
"notes_by_num":{"1":"Buggy. `visibility:collapse` applied to a `<tr>` only hides content and does not \"remove\" it from layout.","2":"Partially supported. `visibility:collapse` is not supported."}
},
@@ -3246,7 +3278,7 @@
"last_test_date":"2024-09-04",
"test_url":"https://www.caniemail.com/tests/css-white-space-collapse.html",
"test_results_url":"https://testi.at/proj/e6y4s3zytp5kty7kcg",
"stats":{"apple-mail":{"macos":{"10":"n","11":"n","12":"n","13":"n","14":"y #1"},"ios":{"15":"y #1"}},"gmail":{"desktop-webmail":{"2024-09":"n"},"ios":{"2024-09":"n"},"android":{"2024-09":"n"},"mobile-webmail":{"2024-09":"n"}},"orange":{"desktop-webmail":{"2024-09":"u"},"ios":{"2024-09":"u"},"android":{"2024-09":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-09":"n"},"macos":{"2024-09":"n"},"outlook-com":{"2024-09":"n"},"ios":{"2024-09":"n"},"android":{"2024-09":"n"}},"yahoo":{"desktop-webmail":{"2024-09":"n"},"ios":{"2024-09":"n"},"android":{"2024-09":"n"}},"aol":{"desktop-webmail":{"2024-09":"n"},"ios":{"2024-09":"n"},"android":{"2024-09":"n"}},"samsung-email":{"android":{"2024-09":"y #1"}},"sfr":{"desktop-webmail":{"2024-03":"u"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"protonmail":{"desktop-webmail":{"2024-09":"u"},"ios":{"2024-09":"u"},"android":{"2024-09":"u"}},"hey":{"desktop-webmail":{"2024-09":"u"}},"mail-ru":{"desktop-webmail":{"2024-09":"y #1"}},"fastmail":{"desktop-webmail":{"2024-09":"u"}}},
"stats":{"apple-mail":{"macos":{"10":"n","11":"n","12":"n","13":"n","14":"y #1"},"ios":{"15":"y #1"}},"gmail":{"desktop-webmail":{"2024-09":"n"},"ios":{"2024-09":"n"},"android":{"2024-09":"n"},"mobile-webmail":{"2024-09":"n"}},"orange":{"desktop-webmail":{"2024-09":"u"},"ios":{"2024-09":"u"},"android":{"2024-09":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-09":"n"},"macos":{"2024-09":"n"},"outlook-com":{"2024-09":"n"},"ios":{"2024-09":"n"},"android":{"2024-09":"n"}},"yahoo":{"desktop-webmail":{"2024-09":"n"},"ios":{"2024-09":"n"},"android":{"2024-09":"n"}},"aol":{"desktop-webmail":{"2024-09":"n"},"ios":{"2024-09":"n"},"android":{"2024-09":"n"}},"samsung-email":{"android":{"2024-09":"y #1"}},"sfr":{"desktop-webmail":{"2024-03":"u"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"protonmail":{"desktop-webmail":{"2024-09":"y"},"ios":{"2024-09":"y"},"android":{"2024-09":"y"}},"hey":{"desktop-webmail":{"2024-09":"u"}},"mail-ru":{"desktop-webmail":{"2024-09":"y #1"}},"fastmail":{"desktop-webmail":{"2024-09":"u"}}},
"notes":null,
"notes_by_num":{"1":"Partial. `preserve-spaces` value works only on Firefox."}
},
@@ -3278,7 +3310,7 @@
"last_test_date":"2024-05-03",
"test_url":"https://www.caniemail.com/tests/css-widows.html",
"test_results_url":"https://testi.at/proj/6vd8udzx1b5l1vrnsr",
"stats":{"apple-mail":{"macos":{"2024-05":"y"},"ios":{"2024-05":"y"}},"gmail":{"desktop-webmail":{"2024-05":"n #4"},"ios":{"2024-05":"n"},"android":{"2024-05":"n #3"},"mobile-webmail":{"2024-05":"n #1 #2"}},"orange":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-05":"n"},"macos":{"2024-05":"y"},"outlook-com":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"yahoo":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"aol":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"samsung-email":{"android":{"2024-05":"y"}},"sfr":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"protonmail":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"hey":{"desktop-webmail":{"2024-05":"u"}},"mail-ru":{"desktop-webmail":{"2024-05":"y #4"}},"fastmail":{"desktop-webmail":{"2024-05":"u"}},"laposte":{"desktop-webmail":{"2021-08":"u"}},"gmx":{"desktop-webmail":{"2024-05":"n #1 #4"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"web-de":{"desktop-webmail":{"2024-05":"n #1 #4"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-05":"u"},"android":{"2024-05":"u"}}},
"stats":{"apple-mail":{"macos":{"2024-05":"y"},"ios":{"2024-05":"y"}},"gmail":{"desktop-webmail":{"2024-05":"n #4"},"ios":{"2024-05":"n"},"android":{"2024-05":"n #3"},"mobile-webmail":{"2024-05":"n #1 #2"}},"orange":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-05":"n"},"macos":{"2024-05":"y"},"outlook-com":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"yahoo":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"aol":{"desktop-webmail":{"2024-05":"n"},"ios":{"2024-05":"n"},"android":{"2024-05":"n"}},"samsung-email":{"android":{"2024-05":"y"}},"sfr":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"protonmail":{"desktop-webmail":{"2024-05":"y #4"},"ios":{"2024-05":"y #4"},"android":{"2024-05":"y #4"}},"hey":{"desktop-webmail":{"2024-05":"u"}},"mail-ru":{"desktop-webmail":{"2024-05":"y #4"}},"fastmail":{"desktop-webmail":{"2024-05":"u"}},"laposte":{"desktop-webmail":{"2021-08":"u"}},"gmx":{"desktop-webmail":{"2024-05":"n #1 #4"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"web-de":{"desktop-webmail":{"2024-05":"n #1 #4"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-05":"u"},"android":{"2024-05":"u"}}},
"notes":null,
"notes_by_num":{"1":"Buggy. `columns` property is stripped which is required for `widows` to work","2":"Buggy. `widows` property value is replaced by `auto`","3":"Not supported, but Gmail's default styles on the email message container includes the `widows` property. These values are inherited by children elements","4":"Webmail rendering depends on browser support"}
},
@@ -3326,11 +3358,27 @@
"last_test_date":"2024-03-13",
"test_url":"https://www.caniemail.com/tests/css-word-spacing.html",
"test_results_url":"https://testi.at/proj/8r8pfrlvcxklca32ij",
"stats":{"apple-mail":{"macos":{"2024-03":"y"},"ios":{"2024-03":"y"}},"gmail":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"},"mobile-webmail":{"2024-03":"y"}},"orange":{"desktop-webmail":{"2024-03":"u"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-03":"n"},"macos":{"2024-03":"y"},"outlook-com":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"yahoo":{"desktop-webmail":{"2024-03":"a #1"},"ios":{"2024-03":"a #1"},"android":{"2024-03":"n"}},"aol":{"desktop-webmail":{"2024-03":"a #1"},"ios":{"2024-03":"a #1"},"android":{"2024-03":"n"}},"samsung-email":{"android":{"2024-03":"y"}},"sfr":{"desktop-webmail":{"2024-03":"u"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"thunderbird":{"macos":{"2024-03":"y"}},"protonmail":{"desktop-webmail":{"2024-03":"u"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"hey":{"desktop-webmail":{"2024-03":"u"}},"mail-ru":{"desktop-webmail":{"2024-03":"y"}},"fastmail":{"desktop-webmail":{"2024-03":"u"}},"laposte":{"desktop-webmail":{"2024-03":"u"}},"gmx":{"desktop-webmail":{"2024-03":"a #1"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"web-de":{"desktop-webmail":{"2024-03":"a #1"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-03":"u"},"android":{"2024-03":"u"}}},
"stats":{"apple-mail":{"macos":{"2024-03":"y"},"ios":{"2024-03":"y"}},"gmail":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"},"mobile-webmail":{"2024-03":"y"}},"orange":{"desktop-webmail":{"2024-03":"u"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"outlook":{"windows":{"2013":"n","2016":"n","2019":"n","2021":"n"},"windows-mail":{"2024-03":"n"},"macos":{"2024-03":"y"},"outlook-com":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"yahoo":{"desktop-webmail":{"2024-03":"a #1"},"ios":{"2024-03":"a #1"},"android":{"2024-03":"n","2025-06":"a #1"}},"aol":{"desktop-webmail":{"2024-03":"a #1"},"ios":{"2024-03":"a #1"},"android":{"2024-03":"n"}},"samsung-email":{"android":{"2024-03":"y"}},"sfr":{"desktop-webmail":{"2024-03":"u"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"thunderbird":{"macos":{"2024-03":"y"}},"protonmail":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"hey":{"desktop-webmail":{"2024-03":"u"}},"mail-ru":{"desktop-webmail":{"2024-03":"y"}},"fastmail":{"desktop-webmail":{"2024-03":"u"}},"laposte":{"desktop-webmail":{"2024-03":"u"}},"gmx":{"desktop-webmail":{"2024-03":"a #1"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"web-de":{"desktop-webmail":{"2024-03":"a #1"},"ios":{"2024-03":"u"},"android":{"2024-03":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-03":"u"},"android":{"2024-03":"u"}}},
"notes":null,
"notes_by_num":{"1":"Does not support `rem` and `ch` values."}
},
{
"slug":"css-word-wrap",
"title":"word-wrap",
"description":"The word-wrap CSS property (now standardized as overflow-wrap) controls whether the browser should break words to prevent them from overflowing their container. When set to break-word, it forces otherwise unbreakable strings to wrap onto the next line to avoid layout issues.",
"url":"https://www.caniemail.com/features/css-word-wrap/",
"category":"css",
"tags":[],
"keywords":"word-wrap, word-break, overflow-wrap",
"last_test_date":"2025-05-08",
"test_url":"https://www.caniemail.com/tests/css-word-wrap.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/vCaPUwbCjmYsdRJi38QdpqJSetV5X7wBQh5iymp8t1Sty/list",
"stats":{"apple-mail":{"macos":{"16":"y"},"ios":{"16":"y"}},"gmail":{"desktop-webmail":{"2025-05":"a #1"},"android":{"2025-05":"a #1"}},"outlook":{"windows":{"2016":"n #2","2019":"n #2","2021":"n #2"},"windows-mail":{"2025-05":"n"},"outlook-com":{"2022-05":"y #3"},"ios":{"2025-05":"y #3"},"android":{"2025-05":"n"}},"yahoo":{"desktop-webmail":{"2025-05":"y"}}},
"notes":null,
"notes_by_num":{"1":"Applies `word-wrap: break-word` to all items.","2":"Does not honor any wrapping, including `word-wrap`, `overflow-wrap`, and `word-break`. Using an equivalent MSO breakdown (`-ms-word-break: break-all` and `mso-hyphenate: none` together) does not work.","3":"Supports both `word-wrap` and equivalent MSO breakdown (`-ms-word-break: break-all` and `mso-hyphenate: none` together)"}
},
{
"slug":"css-writing-mode",
"title":"writing-mode",
@@ -3390,7 +3438,7 @@
"last_test_date":"2024-01-03",
"test_url":"https://www.caniemail.com/tests/html-acronym.html",
"test_results_url":"https://testi.at/proj/ayebhgpxu58yce2bhd",
"stats":{"apple-mail":{"macos":{"2024-01":"y"},"ios":{"2024-01":"y"}},"gmail":{"desktop-webmail":{"2024-01":"y"},"ios":{"2024-01":"y"},"android":{"2024-01":"y"},"mobile-webmail":{"2024-01":"y"}},"orange":{"desktop-webmail":{"2024-01":"u"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"outlook":{"windows":{"2013":"n #1","2016":"n #1","2019":"n #1","2021":"n #1"},"windows-mail":{"2024-01":"n #1"},"macos":{"2024-01":"y"},"outlook-com":{"2024-01":"y"},"ios":{"2024-01":"y"},"android":{"2024-01":"y"}},"samsung-email":{"android":{"2024-01":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"2024-01":"y"}},"aol":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"}},"yahoo":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"}},"protonmail":{"desktop-webmail":{"2024-01":"u"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"hey":{"desktop-webmail":{"2024-01":"u"}},"mail-ru":{"desktop-webmail":{"2024-01":"n"}},"fastmail":{"desktop-webmail":{"2024-01":"u"}},"laposte":{"desktop-webmail":{"2024-01":"u"}},"free-fr":{"desktop-webmail":{"2024-01":"u"}},"t-online-de":{"desktop-webmail":{"2024-01":"y"}},"gmx":{"desktop-webmail":{"2024-01":"y"}},"web-de":{"desktop-webmail":{"2024-01":"y"}}},
"stats":{"apple-mail":{"macos":{"2024-01":"y"},"ios":{"2024-01":"y"}},"gmail":{"desktop-webmail":{"2024-01":"y"},"ios":{"2024-01":"y"},"android":{"2024-01":"y"},"mobile-webmail":{"2024-01":"y"}},"orange":{"desktop-webmail":{"2024-01":"u"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"outlook":{"windows":{"2013":"n #1","2016":"n #1","2019":"n #1","2021":"n #1"},"windows-mail":{"2024-01":"n #1"},"macos":{"2024-01":"y"},"outlook-com":{"2024-01":"y"},"ios":{"2024-01":"y"},"android":{"2024-01":"y"}},"samsung-email":{"android":{"2024-01":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"2024-01":"y"}},"aol":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"}},"yahoo":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"}},"protonmail":{"desktop-webmail":{"2024-01":"y"},"ios":{"2024-01":"y"},"android":{"2024-01":"y"}},"hey":{"desktop-webmail":{"2024-01":"u"}},"mail-ru":{"desktop-webmail":{"2024-01":"n"}},"fastmail":{"desktop-webmail":{"2024-01":"u"}},"laposte":{"desktop-webmail":{"2024-01":"u"}},"free-fr":{"desktop-webmail":{"2024-01":"u"}},"t-online-de":{"desktop-webmail":{"2024-01":"y"}},"gmx":{"desktop-webmail":{"2024-01":"y"}},"web-de":{"desktop-webmail":{"2024-01":"y"}}},
"notes":null,
"notes_by_num":{"1":"Buggy. `title` attribute is removed but keeps `<acronym>` tag."}
},
@@ -3593,7 +3641,7 @@
"description":null,
"url":"https://www.caniemail.com/features/html-blockquote/",
"category":"html",
"tags":[],
"tags":["accessibility"],
"keywords":null,
"last_test_date":"2020-05-08",
"test_url":"https://www.caniemail.com/tests/html-semantics.html",
@@ -3662,7 +3710,7 @@
"last_test_date":"2024-05-01",
"test_url":"https://www.caniemail.com/tests/html-cellspacing.html",
"test_results_url":"https://testi.at/proj/rlpatnzxf3eyce9oc3",
"stats":{"apple-mail":{"macos":{"2024-05":"y"},"ios":{"2024-05":"y"}},"gmail":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"},"mobile-webmail":{"2024-05":"y"}},"orange":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"outlook":{"windows":{"2013":"y","2016":"y","2019":"y","2021":"y"},"windows-mail":{"2024-05":"y"},"macos":{"2024-05":"y"},"outlook-com":{"2024-05":"y","2024-01":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"yahoo":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"aol":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"samsung-email":{"android":{"2024-05":"y"}},"sfr":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"thunderbird":{"macos":{"2024-05":"y"}},"protonmail":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"hey":{"desktop-webmail":{"2024-05":"u"}},"mail-ru":{"desktop-webmail":{"2024-05":"y"}},"fastmail":{"desktop-webmail":{"2024-05":"u"}},"laposte":{"desktop-webmail":{"2024-05":"u"}},"gmx":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"web-de":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-05":"u"},"android":{"2024-05":"u"}}},
"stats":{"apple-mail":{"macos":{"2024-05":"y"},"ios":{"2024-05":"y"}},"gmail":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"},"mobile-webmail":{"2024-05":"y"}},"orange":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"outlook":{"windows":{"2013":"y","2016":"y","2019":"y","2021":"y"},"windows-mail":{"2024-05":"y"},"macos":{"2024-05":"y"},"outlook-com":{"2024-05":"y","2024-01":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"yahoo":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"aol":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"samsung-email":{"android":{"2024-05":"y"}},"sfr":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"thunderbird":{"macos":{"2024-05":"y"}},"protonmail":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"hey":{"desktop-webmail":{"2024-05":"u"}},"mail-ru":{"desktop-webmail":{"2024-05":"y"}},"fastmail":{"desktop-webmail":{"2024-05":"u"}},"laposte":{"desktop-webmail":{"2024-05":"u"}},"gmx":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"web-de":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-05":"u"},"android":{"2024-05":"u"}}},
"notes":null,
"notes_by_num":null
},
@@ -3678,7 +3726,7 @@
"last_test_date":"2024-05-01",
"test_url":"https://www.caniemail.com/tests/html-cellspacing.html",
"test_results_url":"https://testi.at/proj/rlpatnzxf3eyce9oc3",
"stats":{"apple-mail":{"macos":{"2024-05":"y"},"ios":{"2024-05":"y"}},"gmail":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"},"mobile-webmail":{"2024-05":"y"}},"orange":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"outlook":{"windows":{"2013":"y","2016":"y","2019":"y","2021":"y"},"windows-mail":{"2024-05":"y"},"macos":{"2024-05":"y"},"outlook-com":{"2024-05":"y","2024-01":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"yahoo":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"aol":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"samsung-email":{"android":{"2024-05":"y"}},"sfr":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"thunderbird":{"macos":{"2024-05":"y"}},"protonmail":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"hey":{"desktop-webmail":{"2024-05":"u"}},"mail-ru":{"desktop-webmail":{"2024-05":"y"}},"fastmail":{"desktop-webmail":{"2024-05":"u"}},"laposte":{"desktop-webmail":{"2024-05":"u"}},"gmx":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"web-de":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-05":"u"},"android":{"2024-05":"u"}}},
"stats":{"apple-mail":{"macos":{"2024-05":"y"},"ios":{"2024-05":"y"}},"gmail":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"},"mobile-webmail":{"2024-05":"y"}},"orange":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"outlook":{"windows":{"2013":"y","2016":"y","2019":"y","2021":"y"},"windows-mail":{"2024-05":"y"},"macos":{"2024-05":"y"},"outlook-com":{"2024-05":"y","2024-01":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"yahoo":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"aol":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"samsung-email":{"android":{"2024-05":"y"}},"sfr":{"desktop-webmail":{"2024-05":"u"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"thunderbird":{"macos":{"2024-05":"y"}},"protonmail":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"y"},"android":{"2024-05":"y"}},"hey":{"desktop-webmail":{"2024-05":"u"}},"mail-ru":{"desktop-webmail":{"2024-05":"y"}},"fastmail":{"desktop-webmail":{"2024-05":"u"}},"laposte":{"desktop-webmail":{"2024-05":"u"}},"gmx":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"web-de":{"desktop-webmail":{"2024-05":"y"},"ios":{"2024-05":"u"},"android":{"2024-05":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-05":"u"},"android":{"2024-05":"u"}}},
"notes":null,
"notes_by_num":null
},
@@ -3737,12 +3785,12 @@
"description":"It is used to identify a term that is going to be described within the content.",
"url":"https://www.caniemail.com/features/html-dfn/",
"category":"html",
"tags":[],
"tags":["accessibility"],
"keywords":null,
"last_test_date":"2023-09-11",
"test_url":"https://www.caniemail.com/tests/html-dfn.html",
"test_results_url":"https://testi.at/proj/gy2dfo4j19d4176d08y",
"stats":{"apple-mail":{"macos":{"2023-09":"y"},"ios":{"2023-09":"y"}},"gmail":{"desktop-webmail":{"2023-09":"y"},"ios":{"2023-09":"y"},"android":{"2023-09":"y"},"mobile-webmail":{"2023-09":"y"}},"orange":{"desktop-webmail":{"2023-09":"u"},"ios":{"2023-09":"u"},"android":{"2023-09":"u"}},"outlook":{"windows":{"2013":"a #1","2016":"a #1","2019":"a #1","2021":"a #1"},"windows-mail":{"2023-09":"a #1"},"macos":{"16.56":"y","16.80":"y"},"outlook-com":{"2023-09":"y","2024-01":"y"},"ios":{"2023-09":"y"},"android":{"2023-09":"y"}},"samsung-email":{"android":{"2023-09":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"2023-09":"y"}},"aol":{"desktop-webmail":{"2023-09":"y"},"ios":{"2023-09":"y"},"android":{"2023-09":"y"}},"yahoo":{"desktop-webmail":{"2023-09":"y"},"ios":{"2023-09":"y"},"android":{"2023-09":"y"}},"protonmail":{"desktop-webmail":{"2023-09":"u"},"ios":{"2023-09":"u"},"android":{"2023-09":"u"}},"hey":{"desktop-webmail":{"2023-09":"u"}},"mail-ru":{"desktop-webmail":{"2023-09":"n"}},"fastmail":{"desktop-webmail":{"2023-09":"u"}},"laposte":{"desktop-webmail":{"2023-09":"u"}},"free-fr":{"desktop-webmail":{"2023-09":"u"}},"t-online-de":{"desktop-webmail":{"2023-09":"n"}},"gmx":{"desktop-webmail":{"2023-09":"y"}},"web-de":{"desktop-webmail":{"2023-09":"y"}}},
"stats":{"apple-mail":{"macos":{"2023-09":"y"},"ios":{"2023-09":"y"}},"gmail":{"desktop-webmail":{"2023-09":"y"},"ios":{"2023-09":"y"},"android":{"2023-09":"y"},"mobile-webmail":{"2023-09":"y"}},"orange":{"desktop-webmail":{"2023-09":"u"},"ios":{"2023-09":"u"},"android":{"2023-09":"u"}},"outlook":{"windows":{"2013":"a #1","2016":"a #1","2019":"a #1","2021":"a #1"},"windows-mail":{"2023-09":"a #1"},"macos":{"16.56":"y","16.80":"y"},"outlook-com":{"2023-09":"y","2024-01":"y"},"ios":{"2023-09":"y"},"android":{"2023-09":"y"}},"samsung-email":{"android":{"2023-09":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"2023-09":"y"}},"aol":{"desktop-webmail":{"2023-09":"y"},"ios":{"2023-09":"y"},"android":{"2023-09":"y"}},"yahoo":{"desktop-webmail":{"2023-09":"y"},"ios":{"2023-09":"y"},"android":{"2023-09":"y"}},"protonmail":{"desktop-webmail":{"2023-09":"y"},"ios":{"2023-09":"y"},"android":{"2023-09":"y"}},"hey":{"desktop-webmail":{"2023-09":"u"}},"mail-ru":{"desktop-webmail":{"2023-09":"n"}},"fastmail":{"desktop-webmail":{"2023-09":"u"}},"laposte":{"desktop-webmail":{"2023-09":"u"}},"free-fr":{"desktop-webmail":{"2023-09":"u"}},"t-online-de":{"desktop-webmail":{"2023-09":"n"}},"gmx":{"desktop-webmail":{"2023-09":"y"}},"web-de":{"desktop-webmail":{"2023-09":"y"}}},
"notes":null,
"notes_by_num":{"1":"Partial. The `title` attribute is removed."}
},
@@ -3833,7 +3881,7 @@
"description":"Support for headings elements in HTML: `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<h6>`.",
"url":"https://www.caniemail.com/features/html-h1-h6/",
"category":"html",
"tags":[],
"tags":["accessibility"],
"keywords":"headings, h1, h2, h3, h4, h5, h6",
"last_test_date":"2020-05-08",
"test_url":"https://www.caniemail.com/tests/html-semantics.html",
@@ -3870,7 +3918,7 @@
"last_test_date":"2024-01-26",
"test_url":"https://www.caniemail.com/tests/html-hidden-attribute.html",
"test_results_url":"https://testi.at/proj/rlpli9r9trvs62rt7p",
"stats":{"apple-mail":{"macos":{"20":"y","21":"y","22":"y","23":"y"},"ios":{"14":"y","15":"y","16":"y","17":"y"}},"gmail":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"},"mobile-webmail":{"2024-01":"n"}},"orange":{"desktop-webmail":{"2024-01":"u"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2024-01":"n"},"macos":{"2016":"y","2024-01":"n"},"outlook-com":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"}},"samsung-email":{"android":{"6.1":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"yahoo":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"}},"protonmail":{"desktop-webmail":{"2024-01":"u"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"hey":{"desktop-webmail":{"2024-01":"u"}},"mail-ru":{"desktop-webmail":{"2024-01":"a #1"}},"fastmail":{"desktop-webmail":{"2024-01":"u"}},"laposte":{"desktop-webmail":{"2024-01":"u"}},"gmx":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"web-de":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-01":"u"},"android":{"2024-01":"u"}}},
"stats":{"apple-mail":{"macos":{"20":"y","21":"y","22":"y","23":"y"},"ios":{"14":"y","15":"y","16":"y","17":"y"}},"gmail":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"},"mobile-webmail":{"2024-01":"n"}},"orange":{"desktop-webmail":{"2024-01":"u"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"outlook":{"windows":{"2003":"n","2007":"n","2010":"n","2013":"n","2016":"n","2019":"n"},"windows-mail":{"2024-01":"n"},"macos":{"2016":"y","2024-01":"n"},"outlook-com":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"}},"samsung-email":{"android":{"6.1":"y"}},"sfr":{"desktop-webmail":{"2024-03":"y"},"ios":{"2024-03":"y"},"android":{"2024-03":"y"}},"thunderbird":{"macos":{"60.3":"y"}},"aol":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"yahoo":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"n"},"android":{"2024-01":"n"}},"protonmail":{"desktop-webmail":{"2024-01":"y"},"ios":{"2024-01":"y"},"android":{"2024-01":"y"}},"hey":{"desktop-webmail":{"2024-01":"u"}},"mail-ru":{"desktop-webmail":{"2024-01":"a #1"}},"fastmail":{"desktop-webmail":{"2024-01":"u"}},"laposte":{"desktop-webmail":{"2024-01":"u"}},"gmx":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"web-de":{"desktop-webmail":{"2024-01":"n"},"ios":{"2024-01":"u"},"android":{"2024-01":"u"}},"ionos-1and1":{"desktop-webmail":{"2024-01":"u"},"android":{"2024-01":"u"}}},
"notes":null,
"notes_by_num":{"1":"Does not support the unquoted attribute value syntax `<div hidden></div>`"}
},
@@ -4057,7 +4105,7 @@
"description":"Support for lists in HTML: `<ul>`, `<ol>`, `<li>`, `<dl>`, `<dt>` and `<dd>` elements.",
"url":"https://www.caniemail.com/features/html-lists/",
"category":"html",
"tags":[],
"tags":["accessibility"],
"keywords":"ul, ol, li, dl, dt, dd",
"last_test_date":"2024-02-17",
"test_url":"https://www.caniemail.com/tests/css-list.html",
@@ -4121,7 +4169,7 @@
"description":"Changes the default colors of HTML elements. Useful for when you want an email to display only in a dark color scheme or only a light scheme, regardless of user settings. Equivalent to setting the color-scheme CSS property on the root element",
"url":"https://www.caniemail.com/features/html-meta-color-scheme/",
"category":"html",
"tags":[],
"tags":["accessibility"],
"keywords":"dark-mode",
"last_test_date":"2023-09-18",
"test_url":"https://www.caniemail.com/tests/html-meta-color-scheme.html",
@@ -4169,7 +4217,7 @@
"description":null,
"url":"https://www.caniemail.com/features/html-p/",
"category":"html",
"tags":[],
"tags":["accessibility"],
"keywords":"paragraph",
"last_test_date":"2020-05-08",
"test_url":"https://www.caniemail.com/tests/html-semantics.html",
@@ -4313,7 +4361,7 @@
"description":"",
"url":"https://www.caniemail.com/features/html-ruby/",
"category":"html",
"tags":["i18n"],
"tags":["i18n","accessibility"],
"keywords":null,
"last_test_date":"2019-02-28",
"test_url":"https://www.caniemail.com/tests/HTML5.html",
@@ -4345,7 +4393,7 @@
"description":"This includes support for `<article>`, `<aside>`, `<details>`, `<figcaption>`, `<figure>`, `<footer>`, `<header>`, `<main>`, `<mark>`, `<nav>`, `<section>`, `<summary>`, `<time>` elements.",
"url":"https://www.caniemail.com/features/html-semantics/",
"category":"html",
"tags":[],
"tags":["accessibility"],
"keywords":"article, aside, details, figcaption, figure, footer, header, main, mark, nav, section, summary, time",
"last_test_date":"2019-07-29",
"test_url":"https://www.caniemail.com/tests/html-semantics.html",
@@ -4446,9 +4494,9 @@
"last_test_date":"2023-07-27",
"test_url":"https://www.caniemail.com/tests/html-style.html",
"test_results_url":"https://app.emailonacid.com/app/acidtest/CAMb612bxbVwRWPhM4wZKNhhdcdkNxj0Rj6dtRRw6LQUO/list",
"stats":{"apple-mail":{"macos":{"10.3":"y","16.0":"y"},"ios":{"10.3":"y","12.3":"y","16.2":"y"}},"gmail":{"desktop-webmail":{"2019-06":"a #1","2023-01":"a #1"},"ios":{"2019-06":"a #1 #2","2023-01":"a #1 #2"},"android":{"2019-06":"a #1 #2"},"mobile-webmail":{"2020-02":"n","2023-01":"n"}},"orange":{"desktop-webmail":{"2019-06":"y","2021-03":"y","2023-02":"y"},"ios":{"2019-06":"y","2023-02":"y"},"android":{"2019-06":"n","2019-08":"y","2023-02":"y"}},"outlook":{"windows":{"2003":"y","2007":"a #4","2010":"a #4","2013":"a #4","2016":"a #4","2019":"a #4"},"windows-mail":{"2020-01":"a #4","2023-01":"a #4"},"macos":{"2011":"y","2016":"y","2019":"y","2021":"y","16.80":"y"},"outlook-com":{"2019-06":"y","2023-01":"y","2024-01":"y"},"ios":{"2019-06":"y","2023-01":"y"},"android":{"2019-06":"y"}},"samsung-email":{"android":{"5.0.10.2":"y","6.0":"y"}},"sfr":{"desktop-webmail":{"2019-06":"y","2023-02":"y"},"ios":{"2019-06":"n","2023-02":"n"},"android":{"2019-06":"n","2023-02":"n"}},"thunderbird":{"macos":{"60.3":"y","102.7":"y"},"windows":{"102.7":"y"}},"aol":{"desktop-webmail":{"2020-01":"y","2023-01":"y"},"ios":{"2020-01":"y","2023-01":"y"},"android":{"2020-01":"y"}},"yahoo":{"desktop-webmail":{"2019-06":"y #5","2023-01":"y"},"ios":{"2019-06":"y","2023-01":"y"},"android":{"2019-06":"a #3","2023-01":"a #3"}},"protonmail":{"desktop-webmail":{"2020-03":"n","2022-02":"y","2023-01":"y"},"ios":{"2020-03":"n","2023-01":"a #1"},"android":{"2020-03":"a #1"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-09":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y"},"ios":{"2023-02":"n"},"android":{"2023-02":"n"}},"gmx":{"desktop-webmail":{"2022-11":"y","2023-07":"n"},"ios":{"2022-11":"y"},"android":{"2022-11":"y"}},"web-de":{"desktop-webmail":{"2022-11":"y","2025-04":"n"},"ios":{"2022-11":"y"},"android":{"2022-11":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-11":"y"},"android":{"2022-11":"y"}},"rainloop":{"desktop-webmail":{"2023-02":"n"}},"wp-pl":{"desktop-webmail":{"2023-12":"y"}}},
"stats":{"apple-mail":{"macos":{"10.3":"y","16.0":"y"},"ios":{"10.3":"y","12.3":"y","16.2":"y"}},"gmail":{"desktop-webmail":{"2019-06":"a #1","2023-01":"a #1 #6"},"ios":{"2019-06":"a #1 #2","2023-01":"a #1 #2"},"android":{"2019-06":"a #1 #2"},"mobile-webmail":{"2020-02":"n","2023-01":"n"}},"orange":{"desktop-webmail":{"2019-06":"y","2021-03":"y","2023-02":"y"},"ios":{"2019-06":"y","2023-02":"y"},"android":{"2019-06":"n","2019-08":"y","2023-02":"y"}},"outlook":{"windows":{"2003":"y","2007":"a #4","2010":"a #4","2013":"a #4","2016":"a #4","2019":"a #4"},"windows-mail":{"2020-01":"a #4","2023-01":"a #4"},"macos":{"2011":"y","2016":"y","2019":"y","2021":"y","16.80":"y"},"outlook-com":{"2019-06":"y","2023-01":"y","2024-01":"y"},"ios":{"2019-06":"y","2023-01":"y"},"android":{"2019-06":"y"}},"samsung-email":{"android":{"5.0.10.2":"y","6.0":"y"}},"sfr":{"desktop-webmail":{"2019-06":"y","2023-02":"y","2025-07":"n"},"ios":{"2019-06":"n","2023-02":"n","2025-07":"n"},"android":{"2019-06":"n","2023-02":"n"}},"thunderbird":{"macos":{"60.3":"y","102.7":"y"},"windows":{"102.7":"y"}},"aol":{"desktop-webmail":{"2020-01":"y","2023-01":"y"},"ios":{"2020-01":"y","2023-01":"y"},"android":{"2020-01":"y"}},"yahoo":{"desktop-webmail":{"2019-06":"y #5","2023-01":"y"},"ios":{"2019-06":"y","2023-01":"y"},"android":{"2019-06":"a #3","2023-01":"a #3","2025-06":"y"}},"protonmail":{"desktop-webmail":{"2020-03":"n","2022-02":"y","2023-01":"y"},"ios":{"2020-03":"n","2023-01":"a #1"},"android":{"2020-03":"a #1"}},"hey":{"desktop-webmail":{"2020-06":"y"}},"mail-ru":{"desktop-webmail":{"2020-09":"y"}},"fastmail":{"desktop-webmail":{"2021-07":"y"}},"laposte":{"desktop-webmail":{"2021-08":"y","2025-07":"n"},"ios":{"2023-02":"n","2025-07":"n"},"android":{"2023-02":"n"}},"gmx":{"desktop-webmail":{"2022-11":"y","2023-07":"n"},"ios":{"2022-11":"y"},"android":{"2022-11":"y"}},"web-de":{"desktop-webmail":{"2022-11":"y","2025-04":"n"},"ios":{"2022-11":"y"},"android":{"2022-11":"y"}},"ionos-1and1":{"desktop-webmail":{"2022-11":"y"},"android":{"2022-11":"y"}},"rainloop":{"desktop-webmail":{"2023-02":"n"}},"wp-pl":{"desktop-webmail":{"2023-12":"y"}}},
"notes":"",
"notes_by_num":{"1":"Partial. Not supported inside the `<body>`.","2":"Partial. Not supported with non Google accounts.","3":"Buggy. The first `<head>` in the HTML is removed, so `<style>` elements need to be in a second `<head>` element.","4":"Buggy. `<style>` elements need to be declared before their rules are used.","5":"A CSS rule following a CSS comment is ignored. (See [email-bugs#25](https://github.com/hteumeuleu/email-bugs/issues/25).)"}
"notes_by_num":{"1":"Partial. Not supported inside the `<body>`.","2":"Partial. Not supported with non Google accounts.","3":"Buggy. The first `<head>` in the HTML is removed, so `<style>` elements need to be in a second `<head>` element.","4":"Buggy. `<style>` elements need to be declared before their rules are used.","5":"A CSS rule following a CSS comment is ignored. (See [email-bugs#25](https://github.com/hteumeuleu/email-bugs/issues/25).)","6":"The size of the `<style>` tag [is limited to 16 KB](https://github.com/hteumeuleu/email-bugs/issues/90)"}
},
{
@@ -4473,7 +4521,7 @@
"description":null,
"url":"https://www.caniemail.com/features/html-table/",
"category":"html",
"tags":[],
"tags":["accessibility"],
"keywords":null,
"last_test_date":"2019-09-15",
"test_url":"https://www.caniemail.com/tests/html-table.html",

View File

@@ -1,8 +1,11 @@
package htmlcheck
import (
"context"
"errors"
"fmt"
"io"
"net"
"net/http"
"net/url"
"strings"
@@ -141,19 +144,20 @@ func inlineRemoteCSS(h string) (string, error) {
attributes := link.Attr
for _, a := range attributes {
if a.Key == "href" {
if !isURL(a.Val) {
// skip invalid URL
continue
}
if config.BlockRemoteCSSAndFonts {
logger.Log().Debugf("[html-check] skip testing remote CSS content: %s (--block-remote-css-and-fonts)", a.Val)
return h, nil
}
resp, err := downloadToBytes(a.Val)
if !isValidURL(a.Val) {
// skip invalid URL
logger.Log().Warnf("[html-check] ignoring unsupported stylesheet URL: %s", a.Val)
continue
}
resp, err := downloadCSSToBytes(a.Val)
if err != nil {
logger.Log().Warnf("[html-check] failed to download %s", a.Val)
logger.Log().Warnf("[html-check] %s", err.Error())
continue
}
@@ -182,14 +186,20 @@ func inlineRemoteCSS(h string) (string, error) {
return newDoc, nil
}
// DownloadToBytes returns a []byte slice from a URL
func downloadToBytes(url string) ([]byte, error) {
client := http.Client{
Timeout: 5 * time.Second,
// DownloadCSSToBytes returns a []byte slice from a URL.
// It requires the HTTP response code to be 200 and the content-type to be text/css.
// It will download a maximum of 5MB.
func downloadCSSToBytes(url string) ([]byte, error) {
client := newSafeHTTPClient()
req, err := http.NewRequestWithContext(context.TODO(), http.MethodGet, url, nil)
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", "Mailpit HTML Checker/"+config.Version)
// Get the link response data
resp, err := client.Get(url)
resp, err := client.Do(req)
if err != nil {
return nil, err
}
@@ -200,7 +210,17 @@ func downloadToBytes(url string) ([]byte, error) {
return nil, err
}
body, err := io.ReadAll(resp.Body)
ct := strings.ToLower(resp.Header.Get("content-type"))
if !strings.Contains(ct, "text/css") {
err := fmt.Errorf("invalid CSS content-type from %s: \"%s\" (expected \"text/css\")", url, ct)
return nil, err
}
// set a limit on the number of bytes to read - max 5MB
limit := int64(5242880)
limitedReader := &io.LimitedReader{R: resp.Body, N: limit}
body, err := io.ReadAll(limitedReader)
if err != nil {
return nil, err
}
@@ -208,10 +228,12 @@ func downloadToBytes(url string) ([]byte, error) {
return body, nil
}
// Test if str is a URL
func isURL(str string) bool {
// Test if the string is a supported URL.
// The URL must have the "http" or "https" scheme, and must not contain any login info (http://user:pass@<host>).
func isValidURL(str string) bool {
u, err := url.Parse(str)
return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != ""
return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Hostname() != "" && u.User.String() == ""
}
// Test the HTML for inline CSS styles and styling attributes
@@ -249,3 +271,40 @@ func testInlineStyles(doc *goquery.Document) map[string]int {
return matches
}
func newSafeHTTPClient() *http.Client {
dialer := &net.Dialer{
Timeout: 5 * time.Second,
KeepAlive: 30 * time.Second,
}
tr := &http.Transport{
Proxy: nil, // avoid env proxy surprises unless you explicitly want it
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
return dialer.DialContext(ctx, network, address)
},
TLSHandshakeTimeout: 5 * time.Second,
ResponseHeaderTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
IdleConnTimeout: 30 * time.Second,
MaxIdleConns: 50,
}
client := &http.Client{
Transport: tr,
Timeout: 15 * time.Second,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
// re-validate every redirect hop.
if len(via) >= 3 {
return errors.New("too many redirects")
}
if !isValidURL(req.URL.String()) {
return errors.New("invalid redirect URL")
}
return nil
},
}
return client
}

View File

@@ -163,9 +163,9 @@ func (c CanIEmail) getTest(k string) (Warning, error) {
p++
s.Support = "partial"
noteIDS := noteMatch.FindStringSubmatch(fmt.Sprintf("%s", support))
noteIDs := noteMatch.FindStringSubmatch(fmt.Sprintf("%s", support))
for _, id := range noteIDS {
for _, id := range noteIDs {
s.NoteNumber = id
}
}

View File

@@ -31,7 +31,14 @@ var (
</html>`
expectedHTMLLinks = []string{
"http://example.com", "https://example.com", "HTTPS://EXAMPLE.COM", "http://localhost", "https://localhost", "https://127.0.0.1", "http://link with spaces", "http://example.com/?blaah=yes&test=true",
"http://example.com",
"https://example.com",
"HTTPS://EXAMPLE.COM",
"http://localhost",
"https://localhost",
"https://127.0.0.1",
"http://link with spaces",
"http://example.com/?blaah=yes&test=true",
"http://remote-host/style.css", // css
"https://example.com/image.jpg", // images
}
@@ -41,10 +48,18 @@ var (
[http://localhost]
www.google.com < ignored
|||http://example.com/?some=query-string|||
// RFC2396 appendix E states angle brackets are recommended for text/plain emails to
// recognize potential spaces in between the URL
<https://example.com/ link with spaces>
`
expectedTextLinks = []string{
"http://example.com", "https://example.com", "HTTPS://EXAMPLE.COM", "http://localhost", "http://example.com/?some=query-string",
"http://example.com",
"https://example.com",
"HTTPS://EXAMPLE.COM",
"http://localhost",
"http://example.com/?some=query-string",
"https://example.com/ link with spaces",
}
)

View File

@@ -30,9 +30,28 @@ func RunTests(msg *storage.Message, followRedirects bool) (Response, error) {
}
func extractTextLinks(msg *storage.Message) []string {
testLinkRe := regexp.MustCompile(`(?im)([^<]\b)((http|https):\/\/([\-\w@:%_\+'!.~#?,&\/\/=;]+))`)
// RFC2396 appendix E states angle brackets are recommended for text/plain emails to
// recognize potential spaces in between the URL
// @see https://www.rfc-editor.org/rfc/rfc2396#appendix-E
bracketLinkRe := regexp.MustCompile(`(?im)<((http|https):\/\/([\-\w@:%_\+'!.~#?,&\/\/=;][^>]+))>`)
links := []string{}
links = append(links, linkRe.FindAllString(msg.Text, -1)...)
matches := testLinkRe.FindAllStringSubmatch(msg.Text, -1)
for _, match := range matches {
if len(match) > 0 {
links = append(links, match[2])
}
}
angleMatches := bracketLinkRe.FindAllStringSubmatch(msg.Text, -1)
for _, match := range angleMatches {
if len(match) > 0 {
link := strings.ReplaceAll(match[1], "\n", "")
links = append(links, link)
}
}
return links
}

View File

@@ -1,14 +1,20 @@
package linkcheck
import (
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"net/http"
"regexp"
"strings"
"sync"
"time"
"github.com/axllent/mailpit/config"
"github.com/axllent/mailpit/internal/logger"
"github.com/axllent/mailpit/internal/tools"
)
func getHTTPStatuses(links []string, followRedirects bool) []Link {
@@ -34,6 +40,10 @@ func getHTTPStatuses(links []string, followRedirects bool) []Link {
if err != nil {
l.StatusCode = 0
l.Status = httpErrorSummary(err)
if strings.Contains(l.Status, "private/reserved address") {
l.Status = "Blocked private/reserved address"
l.StatusCode = 451
}
} else {
l.StatusCode = code
l.Status = http.StatusText(code)
@@ -57,23 +67,37 @@ func getHTTPStatuses(links []string, followRedirects bool) []Link {
// Do a HEAD request to return HTTP status code
func doHead(link string, followRedirects bool) (int, error) {
if !tools.IsValidLinkURL(link) {
return 0, fmt.Errorf("invalid URL: %s", link)
}
timeout := time.Duration(10 * time.Second)
dialer := &net.Dialer{
Timeout: 10 * time.Second,
KeepAlive: 30 * time.Second,
}
tr := &http.Transport{}
tr := &http.Transport{
DialContext: safeDialContext(dialer),
}
if config.AllowUntrustedTLS {
tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} // #nosec
}
client := http.Client{
Timeout: timeout,
Timeout: 10 * time.Second,
Transport: tr,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
if followRedirects {
return nil
if len(via) >= 3 {
return errors.New("too many redirects")
}
return http.ErrUseLastResponse
if !followRedirects {
return http.ErrUseLastResponse
}
if !tools.IsValidLinkURL(req.URL.String()) {
return fmt.Errorf("blocked redirect to invalid URL: %s", req.URL)
}
return nil
},
}
@@ -92,7 +116,6 @@ func doHead(link string, followRedirects bool) (int, error) {
}
return 0, err
}
return res.StatusCode, nil
@@ -107,8 +130,33 @@ func httpErrorSummary(err error) string {
if !re.MatchString(e) {
return e
}
parts := re.FindAllStringSubmatch(e, -1)
return parts[0][len(parts[0])-1]
}
// SafeDialContext is a custom dialer that checks if the resolved IP addresses are internal before allowing the connection.
func safeDialContext(dialer *net.Dialer) func(ctx context.Context, network, address string) (net.Conn, error) {
return func(ctx context.Context, network, address string) (net.Conn, error) {
host, port, err := net.SplitHostPort(address)
if err != nil {
return nil, err
}
ips, err := net.DefaultResolver.LookupIPAddr(ctx, host)
if err != nil {
return nil, err
}
if !config.AllowInternalHTTPRequests {
for _, ip := range ips {
if tools.IsInternalIP(ip.IP) {
logger.Log().Warnf("[link-check] Blocked HEAD request to private/reserved address: %s (%s)", host, ip)
return nil, fmt.Errorf("blocked request to %s (%s): private/reserved address", host, ip)
}
}
}
return dialer.DialContext(ctx, network, net.JoinHostPort(ips[0].IP.String(), port))
}
}

View File

@@ -84,6 +84,43 @@ func TestPOP3(t *testing.T) {
}
}
t.Log("Checking UIDL with multiple arguments")
_, err = c.Cmd("UIDL", false, 1, 2, 3)
if err == nil {
t.Error("UIDL with multiple arguments should return an error")
return
}
t.Log("Checking UIDL without a message id")
messageIDs, err := c.Uidl(0)
if err != nil {
t.Error(err.Error())
return
}
if len(messageIDs) != 50 {
assertEqual(t, len(messageIDs), 50, "incorrect UIDL message count")
}
t.Log("Checking UIDL with a message ID")
messageIDs, err = c.Uidl(50)
if err != nil {
t.Error(err.Error())
return
}
assertEqual(t, len(messageIDs), 1, "incorrect UIDL message count")
t.Log("Checking UIDL with an invalid message ID")
if _, err := c.Uidl(51); err == nil {
t.Errorf("UIDL 51 should return an error")
return
}
t.Log("Deleting 25 messages")
for i := 1; i <= 25; i++ {

View File

@@ -215,7 +215,7 @@ func handleTransactionCommand(conn net.Conn, cmd string, args []string, messages
for _, m := range messages {
totalSize += m.Size
}
sendResponse(conn, fmt.Sprintf("+OK %d %d", len(messages), int64(totalSize)))
sendResponse(conn, fmt.Sprintf("+OK %d %d", len(messages), totalSize))
case "LIST":
totalSize := uint64(0)
for _, m := range messages {
@@ -229,21 +229,41 @@ func handleTransactionCommand(conn net.Conn, cmd string, args []string, messages
sendResponse(conn, "-ERR no such message")
return
}
sendResponse(conn, fmt.Sprintf("+OK %d %d", nr, int64(messages[nr-1].Size)))
sendResponse(conn, fmt.Sprintf("+OK %d %d", nr, messages[nr-1].Size))
} else {
sendResponse(conn, fmt.Sprintf("+OK %d messages (%d octets)", len(messages), int64(totalSize)))
sendResponse(conn, fmt.Sprintf("+OK %d messages (%d octets)", len(messages), totalSize))
for row, m := range messages {
sendResponse(conn, fmt.Sprintf("%d %d", row+1, int64(m.Size))) // Convert Size to int64 when printing
sendResponse(conn, fmt.Sprintf("%d %d", row+1, m.Size))
}
sendResponse(conn, ".")
}
case "UIDL":
sendResponse(conn, "+OK unique-id listing follows")
for row, m := range messages {
sendResponse(conn, fmt.Sprintf("%d %s", row+1, m.ID))
if len(args) > 1 {
sendResponse(conn, "-ERR UIDL takes at most one argument")
} else if len(args) == 1 {
nr, err := strconv.Atoi(args[0])
if err != nil {
sendResponse(conn, "-ERR no such message")
return
}
if nr < 1 || nr > len(messages) {
sendResponse(conn, "-ERR no such message")
return
}
m := messages[nr-1]
sendResponse(conn, fmt.Sprintf("+OK %d %s", nr, m.ID))
} else {
sendResponse(conn, "+OK unique-id listing follows")
for row, m := range messages {
sendResponse(conn, fmt.Sprintf("%d %s", row+1, m.ID))
}
sendResponse(conn, ".")
}
sendResponse(conn, ".")
case "RETR":
if len(args) != 1 {
sendResponse(conn, "-ERR no such message")

View File

@@ -32,7 +32,7 @@ var (
)
// InitMetrics initializes all Prometheus metrics
func InitMetrics() {
func initMetrics() {
// Create metrics
totalMessages = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "mailpit_messages",
@@ -107,8 +107,8 @@ func InitMetrics() {
}
// UpdateMetrics updates all metrics with current values
func UpdateMetrics() {
info := stats.Load()
func updateMetrics() {
info := stats.Load(false)
totalMessages.Set(float64(info.Messages))
unreadMessages.Set(float64(info.Unread))
@@ -130,7 +130,7 @@ func UpdateMetrics() {
}
}
// Returns the Prometheus handler & disables double compression in middleware
// GetHandler returns the Prometheus handler & disables double compression in middleware
func GetHandler() http.Handler {
return promhttp.HandlerFor(Registry, promhttp.HandlerOpts{
DisableCompression: true,
@@ -139,8 +139,8 @@ func GetHandler() http.Handler {
// StartUpdater starts the periodic metrics update routine
func StartUpdater() {
InitMetrics()
UpdateMetrics()
initMetrics()
updateMetrics()
// Start periodic updates
go func() {
@@ -148,7 +148,7 @@ func StartUpdater() {
defer ticker.Stop()
for range ticker.C {
UpdateMetrics()
updateMetrics()
}
}()
}
@@ -165,8 +165,9 @@ func StartSeparateServer() {
// Create a dedicated server instance
server := &http.Server{
Addr: config.PrometheusListen,
Handler: mux,
Addr: config.PrometheusListen,
Handler: mux,
ReadHeaderTimeout: 5 * time.Second,
}
// Start HTTP server

View File

@@ -4,25 +4,31 @@ import (
"crypto/tls"
"fmt"
"net/smtp"
"os"
"strings"
"github.com/axllent/mailpit/config"
"github.com/axllent/mailpit/internal/logger"
"github.com/axllent/mailpit/internal/tools"
"github.com/pkg/errors"
)
// Wrapper to forward messages if configured
func autoForwardMessage(from string, data *[]byte) {
func autoForwardMessage(from string, data *[]byte) error {
if config.SMTPForwardConfig.Host == "" {
return
return nil
}
if err := forward(from, *data); err != nil {
logger.Log().Errorf("[forward] error: %s", err.Error())
} else {
logger.Log().Debugf("[forward] message from %s to %s via %s:%d",
from, config.SMTPForwardConfig.To, config.SMTPForwardConfig.Host, config.SMTPForwardConfig.Port)
return errors.WithMessage(err, "[forward] error: %s")
}
logger.Log().Debugf(
"[forward] message from %s to %s via %s:%d",
from, config.SMTPForwardConfig.To, config.SMTPForwardConfig.Host, config.SMTPForwardConfig.Port,
)
return nil
}
func createForwardingSMTPClient(config config.SMTPForwardConfigStruct, addr string) (*smtp.Client, error) {
@@ -50,6 +56,13 @@ func createForwardingSMTPClient(config config.SMTPForwardConfigStruct, addr stri
return nil, fmt.Errorf("error connecting to %s: %v", addr, err)
}
// Set the hostname for HELO/EHLO
if hostname, err := os.Hostname(); err == nil {
if err := client.Hello(hostname); err != nil {
return nil, fmt.Errorf("error saying HELO/EHLO to %s: %v", addr, err)
}
}
if config.STARTTLS {
tlsConf := &tls.Config{ServerName: config.Host} // #nosec
tlsConf.InsecureSkipVerify = config.AllowInsecure
@@ -100,6 +113,9 @@ func forward(from string, msg []byte) error {
for _, addr := range to {
if err = c.Rcpt(addr); err != nil {
logger.Log().Warnf("error response to RCPT command for %s: %s", addr, err.Error())
if config.SMTPForwardConfig.ForwardSMTPErrors {
return errors.WithMessagef(err, "error response to RCPT command for %s", addr)
}
}
}

View File

@@ -17,6 +17,7 @@ import (
"github.com/axllent/mailpit/internal/tools"
"github.com/axllent/mailpit/server/websockets"
"github.com/lithammer/shortuuid/v4"
"github.com/pkg/errors"
)
var (
@@ -73,10 +74,36 @@ func SaveToDatabase(origin net.Addr, from string, to []string, data []byte, smtp
}
// if enabled, this may conditionally relay the email through to the preconfigured smtp server
autoRelayMessage(from, to, &data)
if relayErr := autoRelayMessage(from, to, &data); relayErr != nil {
logger.Log().Error(relayErr.Error())
if config.SMTPRelayConfig.ForwardSMTPErrors {
for {
unwrappedErr := errors.Unwrap(relayErr)
if unwrappedErr == nil {
break
}
relayErr = unwrappedErr
}
return "", relayErr
}
}
// if enabled, this will forward a copy to preconfigured addresses
autoForwardMessage(from, &data)
if forwardErr := autoForwardMessage(from, &data); forwardErr != nil {
logger.Log().Error(forwardErr.Error())
if config.SMTPForwardConfig.ForwardSMTPErrors {
for {
unwrappedErr := errors.Unwrap(forwardErr)
if unwrappedErr == nil {
break
}
forwardErr = unwrappedErr
}
return "", forwardErr
}
}
// build array of all addresses in the header to compare to the []to array
emails, hasBccHeader := scanAddressesInHeader(msg.Header)
@@ -194,15 +221,16 @@ func listenAndServe(addr string, handler MsgIDHandler, authHandler AuthHandler)
Debug = true // to enable Mailpit logging
srv := &Server{
Addr: addr,
MsgIDHandler: handler,
HandlerRcpt: handlerRcpt,
AppName: "Mailpit",
Hostname: "",
AuthHandler: nil,
AuthRequired: false,
MaxRecipients: config.SMTPMaxRecipients,
DisableReverseDNS: DisableReverseDNS,
Addr: addr,
MsgIDHandler: handler,
HandlerRcpt: handlerRcpt,
AppName: "Mailpit",
Hostname: "",
AuthHandler: nil,
AuthRequired: false,
MaxRecipients: config.SMTPMaxRecipients,
IgnoreRejectedRecipients: config.SMTPIgnoreRejectedRecipients,
DisableReverseDNS: DisableReverseDNS,
LogRead: func(remoteIP, verb, line string) {
logger.Log().Debugf("[smtpd] %s (%s) %s", verbLogTranslator(verb), remoteIP, line)
},
@@ -224,15 +252,27 @@ func listenAndServe(addr string, handler MsgIDHandler, authHandler AuthHandler)
}
if config.SMTPAuthAllowInsecure {
srv.AuthMechs = map[string]bool{"CRAM-MD5": false, "PLAIN": true, "LOGIN": true}
srv.AuthMechs = map[string]bool{
"CRAM-MD5": false,
"PLAIN": true,
"LOGIN": true,
}
}
if auth.SMTPCredentials != nil {
srv.AuthMechs = map[string]bool{"CRAM-MD5": false, "PLAIN": true, "LOGIN": true}
srv.AuthMechs = map[string]bool{
"CRAM-MD5": false,
"PLAIN": true,
"LOGIN": true,
}
srv.AuthHandler = authHandler
srv.AuthRequired = true
} else if config.SMTPAuthAcceptAny {
srv.AuthMechs = map[string]bool{"CRAM-MD5": false, "PLAIN": true, "LOGIN": true}
srv.AuthMechs = map[string]bool{
"CRAM-MD5": false,
"PLAIN": true,
"LOGIN": true,
}
srv.AuthHandler = authHandlerAny
}

View File

@@ -2,18 +2,19 @@ package smtpd
import (
"crypto/tls"
"errors"
"fmt"
"net/smtp"
"os"
"strings"
"github.com/axllent/mailpit/config"
"github.com/axllent/mailpit/internal/logger"
"github.com/axllent/mailpit/internal/tools"
"github.com/pkg/errors"
)
// Wrapper to auto relay messages if configured
func autoRelayMessage(from string, to []string, data *[]byte) {
func autoRelayMessage(from string, to []string, data *[]byte) error {
if config.SMTPRelayConfig.BlockedRecipientsRegexp != nil {
filteredTo := []string{}
for _, address := range to {
@@ -28,16 +29,18 @@ func autoRelayMessage(from string, to []string, data *[]byte) {
}
if len(to) == 0 {
return
return nil
}
if config.SMTPRelayAll {
if err := Relay(from, to, *data); err != nil {
logger.Log().Errorf("[relay] error: %s", err.Error())
} else {
logger.Log().Debugf("[relay] sent message to %s from %s via %s:%d",
strings.Join(to, ", "), from, config.SMTPRelayConfig.Host, config.SMTPRelayConfig.Port)
return errors.WithMessage(err, "[relay] error")
}
logger.Log().Debugf(
"[relay] sent message to %s from %s via %s:%d",
strings.Join(to, ", "), from, config.SMTPRelayConfig.Host, config.SMTPRelayConfig.Port,
)
} else if config.SMTPRelayMatchingRegexp != nil {
filtered := []string{}
for _, t := range to {
@@ -47,16 +50,20 @@ func autoRelayMessage(from string, to []string, data *[]byte) {
}
if len(filtered) == 0 {
return
return nil
}
if err := Relay(from, filtered, *data); err != nil {
logger.Log().Errorf("[relay] error: %s", err.Error())
} else {
logger.Log().Debugf("[relay] auto-relay message to %s from %s via %s:%d",
strings.Join(filtered, ", "), from, config.SMTPRelayConfig.Host, config.SMTPRelayConfig.Port)
return errors.WithMessage(err, "[relay] error")
}
logger.Log().Debugf(
"[relay] auto-relay message to %s from %s via %s:%d",
strings.Join(filtered, ", "), from, config.SMTPRelayConfig.Host, config.SMTPRelayConfig.Port,
)
}
return nil
}
func createRelaySMTPClient(config config.SMTPRelayConfigStruct, addr string) (*smtp.Client, error) {
@@ -84,6 +91,13 @@ func createRelaySMTPClient(config config.SMTPRelayConfigStruct, addr string) (*s
return nil, fmt.Errorf("error connecting to %s: %v", addr, err)
}
// Set the hostname for HELO/EHLO
if hostname, err := os.Hostname(); err == nil {
if err := client.Hello(hostname); err != nil {
return nil, fmt.Errorf("error saying HELO/EHLO to %s: %v", addr, err)
}
}
if config.STARTTLS {
tlsConf := &tls.Config{ServerName: config.Host} // #nosec
tlsConf.InsecureSkipVerify = config.AllowInsecure
@@ -126,26 +140,29 @@ func Relay(from string, to []string, msg []byte) error {
}
if err = c.Mail(from); err != nil {
return fmt.Errorf("error response to MAIL command: %s", err.Error())
return errors.WithMessage(err, "error sending MAIL command")
}
for _, addr := range to {
if err = c.Rcpt(addr); err != nil {
logger.Log().Warnf("error response to RCPT command for %s: %s", addr, err.Error())
if config.SMTPRelayConfig.ForwardSMTPErrors {
return errors.WithMessagef(err, "error response to RCPT command for %s", addr)
}
}
}
w, err := c.Data()
if err != nil {
return fmt.Errorf("error response to DATA command: %s", err.Error())
return errors.WithMessage(err, "error response to DATA command")
}
if _, err := w.Write(msg); err != nil {
return fmt.Errorf("error sending message: %s", err.Error())
return errors.WithMessage(err, "error sending message")
}
if err := w.Close(); err != nil {
return fmt.Errorf("error closing connection: %s", err.Error())
return errors.WithMessage(err, "error closing connection")
}
return c.Quit()
@@ -178,7 +195,10 @@ type loginAuth struct {
// LoginAuth authentication
func LoginAuth(username, password string) smtp.Auth {
return &loginAuth{username, password}
return &loginAuth{
username,
password,
}
}
func (a *loginAuth) Start(_ *smtp.ServerInfo) (string, []byte, error) {

View File

@@ -15,6 +15,7 @@ import (
"io/fs"
"log"
"net"
"net/mail"
"os"
"regexp"
"strconv"
@@ -92,26 +93,27 @@ type LogFunc func(remoteIP, verb, line string)
// Server is an SMTP server.
type Server struct {
Addr string // TCP address to listen on, defaults to ":25" (all addresses, port 25) if empty
AppName string
AuthHandler AuthHandler
AuthMechs map[string]bool // Override list of allowed authentication mechanisms. Currently supported: LOGIN, PLAIN, CRAM-MD5. Enabling LOGIN and PLAIN will reduce RFC 4954 compliance.
AuthRequired bool // Require authentication for every command except AUTH, EHLO, HELO, NOOP, RSET or QUIT as per RFC 4954. Ignored if AuthHandler is not configured.
DisableReverseDNS bool // Disable reverse DNS lookups, enforces "unknown" hostname
Handler Handler
HandlerRcpt HandlerRcpt
Hostname string
LogRead LogFunc
LogWrite LogFunc
MaxSize int // Maximum message size allowed, in bytes
MaxRecipients int // Maximum number of recipients, defaults to 100.
MsgIDHandler MsgIDHandler
Timeout time.Duration
TLSConfig *tls.Config
TLSListener bool // Listen for incoming TLS connections only (not recommended as it may reduce compatibility). Ignored if TLS is not configured.
TLSRequired bool // Require TLS for every command except NOOP, EHLO, STARTTLS, or QUIT as per RFC 3207. Ignored if TLS is not configured.
Protocol string // Default tcp, supports unix
SocketPerm fs.FileMode // if using Unix socket, socket permissions
Addr string // TCP address to listen on, defaults to ":25" (all addresses, port 25) if empty
AppName string
AuthHandler AuthHandler
AuthMechs map[string]bool // Override list of allowed authentication mechanisms. Currently supported: LOGIN, PLAIN, CRAM-MD5. Enabling LOGIN and PLAIN will reduce RFC 4954 compliance.
AuthRequired bool // Require authentication for every command except AUTH, EHLO, HELO, NOOP, RSET or QUIT as per RFC 4954. Ignored if AuthHandler is not configured.
DisableReverseDNS bool // Disable reverse DNS lookups, enforces "unknown" hostname
Handler Handler
HandlerRcpt HandlerRcpt
Hostname string
LogRead LogFunc
LogWrite LogFunc
MaxSize int // Maximum message size allowed, in bytes
MaxRecipients int // Maximum number of recipients, defaults to 100.
MsgIDHandler MsgIDHandler
IgnoreRejectedRecipients bool // Accept emails to rejected recipients with 2xx response but silently drop them
Timeout time.Duration
TLSConfig *tls.Config
TLSListener bool // Listen for incoming TLS connections only (not recommended as it may reduce compatibility). Ignored if TLS is not configured.
TLSRequired bool // Require TLS for every command except NOOP, EHLO, STARTTLS, or QUIT as per RFC 3207. Ignored if TLS is not configured.
Protocol string // Default tcp, supports unix
SocketPerm fs.FileMode // if using Unix socket, socket permissions
inShutdown int32 // server was closed or shutdown
openSessions int32 // count of open sessions
@@ -360,9 +362,11 @@ func (s *session) serve() {
// otherwise results in a 5s timeout for each connection
defer func(c net.Conn) { _ = c.Close() }(s.conn)
var gotEHLO bool
var from string
var gotFrom bool
var gotFROM bool
var to []string
var hasRejectedRecipients bool
var buffer bytes.Buffer
// RFC 5321 specifies support for minimum of 100 recipients is required.
@@ -394,18 +398,22 @@ loop:
s.writef("250 %s greets %s", s.srv.Hostname, s.remoteName)
// RFC 2821 section 4.1.4 specifies that EHLO has the same effect as RSET, so reset for HELO too.
gotEHLO = true
from = ""
gotFrom = false
gotFROM = false
to = nil
hasRejectedRecipients = false
buffer.Reset()
case "EHLO":
s.remoteName = args
s.writef("%s", s.makeEHLOResponse())
// RFC 2821 section 4.1.4 specifies that EHLO has the same effect as RSET.
gotEHLO = true
from = ""
gotFrom = false
gotFROM = false
to = nil
hasRejectedRecipients = false
buffer.Reset()
case "MAIL":
if s.srv.TLSConfig != nil && s.srv.TLSRequired && !s.tls {
@@ -416,10 +424,22 @@ loop:
s.writef("530 5.7.0 Authentication required")
break
}
if !gotEHLO {
s.writef("503 5.5.1 Bad sequence of commands (HELO/EHLO required before MAIL)")
break
}
if to != nil {
s.writef("503 5.5.1 Bad sequence of commands (RSET/HELO/EHLO required before MAIL)")
break
}
match := mailFromRE.FindStringSubmatch(args)
match, err := extractAndValidateAddress(mailFromRE, args)
if match == nil {
s.writef("501 5.5.4 Syntax error in parameters or arguments (invalid FROM parameter)")
if err != nil {
s.writef("%s", err.Error())
} else {
s.writef("501 5.5.4 Syntax error in parameters or arguments (invalid FROM parameter)")
}
} else {
// Mailpit Chaos
if fail, code := chaos.Config.Sender.Trigger(); fail {
@@ -433,7 +453,7 @@ loop:
if sizeMatch == nil {
// ignore other parameter
from = match[1]
gotFrom = true
gotFROM = true
s.writef("250 2.1.0 Ok")
} else {
// Enforce the maximum message size if one is set.
@@ -445,18 +465,19 @@ loop:
s.writef("%s", err.Error())
} else { // SIZE ok
from = match[1]
gotFrom = true
gotFROM = true
s.writef("250 2.1.0 Ok")
}
}
} else { // No parameters after FROM
from = match[1]
gotFrom = true
gotFROM = true
s.writef("250 2.1.0 Ok")
}
}
to = nil
hasRejectedRecipients = false
buffer.Reset()
case "RCPT":
if s.srv.TLSConfig != nil && s.srv.TLSRequired && !s.tls {
@@ -467,14 +488,18 @@ loop:
s.writef("530 5.7.0 Authentication required")
break
}
if !gotFrom {
if !gotFROM {
s.writef("503 5.5.1 Bad sequence of commands (MAIL required before RCPT)")
break
}
match := rcptToRE.FindStringSubmatch(args)
match, err := extractAndValidateAddress(rcptToRE, args)
if match == nil {
s.writef("501 5.5.4 Syntax error in parameters or arguments (invalid TO parameter)")
if err != nil {
s.writef("%s", err.Error())
} else {
s.writef("501 5.5.4 Syntax error in parameters or arguments (invalid TO parameter)")
}
} else {
// Mailpit Chaos
if fail, code := chaos.Config.Recipient.Trigger(); fail {
@@ -492,6 +517,9 @@ loop:
if accept {
to = append(to, match[1])
s.writef("250 2.1.5 Ok")
} else if s.srv.IgnoreRejectedRecipients {
hasRejectedRecipients = true
s.writef("250 2.1.5 Ok")
} else {
s.writef("550 5.1.0 Requested action not taken: mailbox unavailable")
}
@@ -506,7 +534,8 @@ loop:
s.writef("530 5.7.0 Authentication required")
break
}
if !gotFrom || len(to) == 0 {
hasRecipients := len(to) > 0 || hasRejectedRecipients
if !gotFROM || !hasRecipients {
s.writef("503 5.5.1 Bad sequence of commands (MAIL & RCPT required before DATA)")
break
}
@@ -536,11 +565,13 @@ loop:
// Create Received header & write message body into buffer.
buffer.Reset()
buffer.Write(s.makeHeaders(to))
if len(to) > 0 {
buffer.Write(s.makeHeaders(to))
}
buffer.Write(data)
// Pass mail on to handler.
if s.srv.Handler != nil {
// Pass mail on to handler only if there are valid recipients.
if len(to) > 0 && s.srv.Handler != nil {
err := s.srv.Handler(s.conn.RemoteAddr(), from, to, buffer.Bytes())
if err != nil {
checkErrFormat := regexp.MustCompile(`^([2-5][0-9]{2})[\s\-](.+)$`)
@@ -552,7 +583,7 @@ loop:
break
}
s.writef("250 2.0.0 Ok: queued")
} else if s.srv.MsgIDHandler != nil {
} else if len(to) > 0 && s.srv.MsgIDHandler != nil {
msgID, err := s.srv.MsgIDHandler(s.conn.RemoteAddr(), from, to, buffer.Bytes(), s.username)
if err != nil {
checkErrFormat := regexp.MustCompile(`^([2-5][0-9]{2})[\s\-](.+)$`)
@@ -570,13 +601,21 @@ loop:
s.writef("250 2.0.0 Ok: queued")
}
} else {
if hasRejectedRecipients && Debug {
if s.srv.LogWrite != nil {
s.srv.LogWrite(s.remoteIP, "DEBUG", "Message from sender silently dropped (rejected recipients)")
} else {
log.Printf("%s DEBUG Message from sender silently dropped (rejected recipients)", s.remoteIP)
}
}
s.writef("250 2.0.0 Ok: queued")
}
// Reset for next mail.
from = ""
gotFrom = false
gotFROM = false
to = nil
hasRejectedRecipients = false
buffer.Reset()
case "QUIT":
s.writef("221 2.0.0 %s %s ESMTP Service closing transmission channel", s.srv.Hostname, s.srv.AppName)
@@ -588,8 +627,9 @@ loop:
}
s.writef("250 2.0.0 Ok")
from = ""
gotFrom = false
gotFROM = false
to = nil
hasRejectedRecipients = false
buffer.Reset()
case "NOOP":
s.writef("250 2.0.0 Ok")
@@ -664,8 +704,9 @@ loop:
// RFC 3207 specifies that the server must discard any prior knowledge obtained from the client.
s.remoteName = ""
from = ""
gotFrom = false
gotFROM = false
to = nil
hasRejectedRecipients = false
buffer.Reset()
case "AUTH":
if s.srv.TLSConfig != nil && s.srv.TLSRequired && !s.tls {
@@ -685,7 +726,7 @@ loop:
}
// RFC 4954 specifies that AUTH is not permitted during mail transactions.
if gotFrom || len(to) > 0 {
if gotFROM || len(to) > 0 {
s.writef("503 5.5.1 Bad sequence of commands (AUTH not permitted during mail transaction)")
break
}
@@ -887,6 +928,10 @@ func (s *session) makeEHLOResponse() (response string) {
}
response += "250-ENHANCEDSTATUSCODES\r\n"
// RFC 6531 specifies that the presence of SMTPUTF8 should include 8BITMIME
// "Servers offering this extension MUST provide support for, and announce, the 8BITMIME extension"
// https://www.rfc-editor.org/rfc/rfc6531#section-3.1:
response += "250-8BITMIME\r\n"
response += "250 SMTPUTF8" // last entry must use a space instead of a dash
return
}
@@ -954,6 +999,12 @@ func (s *session) handleAuthPlain(arg string) (bool, error) {
// Validate credentials.
authenticated, err := s.srv.AuthHandler(s.conn.RemoteAddr(), "PLAIN", parts[1], parts[2], nil)
if authenticated {
uname := string(parts[1])
s.username = &uname
} else {
s.username = nil
}
return authenticated, err
}
@@ -987,3 +1038,35 @@ func (s *session) handleAuthCramMD5() (bool, error) {
return authenticated, err
}
// Extract and validate email address from a regex match.
// This ensures that only RFC 5322 compliant email addresses are accepted (if set).
func extractAndValidateAddress(re *regexp.Regexp, args string) ([]string, error) {
match := re.FindStringSubmatch(args)
if match == nil {
return nil, nil
}
if strings.Contains(match[1], " ") {
return nil, errors.New("553 5.1.3 The address is not a valid RFC 5321 address")
}
// first argument will be the email address, validate it if not empty
if match[1] != "" {
a, err := mail.ParseAddress(match[1])
if err != nil {
return nil, errors.New("553 5.1.3 The address is not a valid RFC 5321 address")
}
// https://datatracker.ietf.org/doc/html/rfc5321#section-4.5.3.1
// RFC states that the local part of an email address SHOULD not exceed 64 characters
// and the domain part SHOULD not exceed 255 characters, however as per https://github.com/axllent/mailpit/issues/620
// it appears that investigated mail servers do not actually implement this limit, but rather enforce
// a much larger limit (ie: 1024 characters).
if len(a.Address) > 1024 {
return nil, errors.New("500 The address is too long")
}
}
return match, nil
}

View File

@@ -104,6 +104,19 @@ func TestCmdEHLO(t *testing.T) {
// See RFC 2821 section 4.1.4 for more detail.
cmdCode(t, conn, "MAIL FROM:<sender@example.com>", "250")
cmdCode(t, conn, "RCPT TO:<recipient@example.com>", "250")
// test invalid addresses & header injection
cmdCode(t, conn, "RCPT TO: <recipientrecipientrecipientreciprecipientrecipientrecipientreciptrecipientrecipientrecipientreciprecipientrecipientrecipientreciptrecipientrecipientrecipientreciprecipientrecipientrecipientreciptrecipientrecipientrecipientreciprecipientrecipientrecipientreciptrecipientrecipientrecipientreciprecipientrecipientrecipientreciptrecipientrecipientrecipientreciprecipientrecipientrecipientreciptrecipientrecipientrecipientreciprecipientrecipientrecipientreciptrecipientrecipientrecipientreciprecipientrecipientrecipientreciptrecipientrecipientrecipientreciprecipientrecipientrecipientreciptrecipientrecipientrecipientreciprecipientrecipientrecipientreciptrecipientrecipientrecipientreciprecipientrecipientrecipientreciptrecipientrecipientrecipientreciprecipientrecipientrecipientreciptrecipientrecipientrecipientreciprecipientrecipientrecipientreciptrecipientrecipientrecipientreciprecipientrecipientrecipientreciptrecipientrecipientrecipient@exampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexample.com>", "500") // too long
cmdCode(t, conn, "RCPT TO:<recipientexample.com>", "553")
cmdCode(t, conn, "RCPT TO: <recipient@test@example.com>", "553")
cmdCode(t, conn, "RCPT TO: <recipient@@example.com>", "553")
cmdCode(t, conn, "RCPT TO: <recipientexample.com>", "553")
cmdCode(t, conn, "RCPT TO: <recipientexample.com>", "501")
cmdCode(t, conn, "RCPT TO:<recipient\rexample.com>", "553")
cmdCode(t, conn, "RCPT TO: <recipient\rexample.com>", "553")
cmdCode(t, conn, "RCPT TO: <recipient\rexample.com>", "501")
cmdCode(t, conn, "RCPT TO: <>", "501") // empty address not allowed here
cmdCode(t, conn, "EHLO host.example.com", "250")
cmdCode(t, conn, "DATA", "503")
@@ -111,6 +124,41 @@ func TestCmdEHLO(t *testing.T) {
_ = conn.Close()
}
func TestCmdMAILBeforeEHLO(t *testing.T) {
conn := newConn(t, &Server{})
// RFC 5321 §4.1.4 — Order of Commands states (emphasis added):
// “The SMTP client MUST issue HELO or EHLO before any other SMTP commands.”
cmdCode(t, conn, "MAIL FROM:<sender@example.com>", "503")
cmdCode(t, conn, "QUIT", "221")
_ = conn.Close()
}
func TestCmdMAILAfterRCPT(t *testing.T) {
conn := newConn(t, &Server{})
// Send EHLO, expect greeting
cmdCode(t, conn, "EHLO host.example.com", "250")
// Send MAIL FROM
cmdCode(t, conn, "MAIL FROM:<sender@example.com>", "250")
// Send RCPT TO
cmdCode(t, conn, "RCPT TO:<recipient@example.com>", "250")
// MAIL FROM must not come after RCPT TO in the same transaction
cmdCode(t, conn, "MAIL FROM:<sender2@example.com>", "503")
// RSET to clear the transaction
cmdCode(t, conn, "RSET", "250")
// Now the MAIL FROM should be accepted
cmdCode(t, conn, "MAIL FROM:<sender2@example.com>", "250")
cmdCode(t, conn, "QUIT", "221")
_ = conn.Close()
}
func TestCmdRSET(t *testing.T) {
conn := newConn(t, &Server{})
cmdCode(t, conn, "EHLO host.example.com", "250")
@@ -131,7 +179,7 @@ func TestCmdMAIL(t *testing.T) {
// MAIL with no FROM arg should return 501 syntax error
cmdCode(t, conn, "MAIL", "501")
// MAIL with empty FROM arg should return 501 syntax error
// // MAIL with empty FROM arg should return 501 syntax error
cmdCode(t, conn, "MAIL FROM:", "501")
cmdCode(t, conn, "MAIL FROM: ", "501")
cmdCode(t, conn, "MAIL FROM: ", "501")
@@ -145,6 +193,20 @@ func TestCmdMAIL(t *testing.T) {
// MAIL with seemingly valid but noncompliant FROM arg (double space after the colon) should return 501 syntax error
cmdCode(t, conn, "MAIL FROM: <sender@example.com>", "501")
// test invalid addresses & header injection
cmdCode(t, conn, "MAIL FROM: <sendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersendersender@exampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexampleexample.com>", "500") // too long
cmdCode(t, conn, "MAIL FROM:<sender\rexample.com>", "553")
cmdCode(t, conn, "MAIL FROM: <sender\rexample.com>", "553")
cmdCode(t, conn, "MAIL FROM: <sender\rexample.com>", "501")
cmdCode(t, conn, "MAIL FROM:<senderexample.com>", "553")
cmdCode(t, conn, "MAIL FROM: <sender@@example.com>", "553")
cmdCode(t, conn, "MAIL FROM: <sender@test@example.com>", "553")
cmdCode(t, conn, "MAIL FROM: <senderexample.com>", "553")
cmdCode(t, conn, "MAIL FROM: <senderexample.com>", "501")
cmdCode(t, conn, "MAIL FROM: < sender@example.com >", "553")
cmdCode(t, conn, "MAIL FROM: < sender@example.com>", "553")
cmdCode(t, conn, "MAIL FROM: <sender@example.com >", "553")
// MAIL with valid SIZE parameter should return 250 Ok
cmdCode(t, conn, "MAIL FROM:<sender@example.com> SIZE=1000", "250")
@@ -153,10 +215,10 @@ func TestCmdMAIL(t *testing.T) {
cmdCode(t, conn, "MAIL FROM:<sender@example.com> SIZE= ", "501")
cmdCode(t, conn, "MAIL FROM:<sender@example.com> SIZE=foo", "501")
// MAIL with options should be ignored except for SIZE
cmdCode(t, conn, "MAIL FROM:<sender@example.com> BODY=8BITMIME", "250") // ignored
cmdCode(t, conn, "MAIL FROM:<sender@example.com> BODY=8BITMIME,SIZE=1000", "250") // size detected
cmdCode(t, conn, "MAIL FROM:<sender@example.com> BODY=8BITMIME,SIZE=foo", "501") // ignored
// MAIL with BODY parameter should be accepted (8BITMIME support)
cmdCode(t, conn, "MAIL FROM:<sender@example.com> BODY=8BITMIME", "250")
cmdCode(t, conn, "MAIL FROM:<sender@example.com> BODY=8BITMIME,SIZE=1000", "250")
cmdCode(t, conn, "MAIL FROM:<sender@example.com> BODY=8BITMIME,SIZE=foo", "501") // SIZE validation error
// TODO: MAIL with valid AUTH parameter should return 250 Ok
@@ -212,6 +274,7 @@ func TestCmdRCPT(t *testing.T) {
cmdCode(t, conn, "RCPT TO:", "501")
cmdCode(t, conn, "RCPT TO: ", "501")
cmdCode(t, conn, "RCPT TO: ", "501")
cmdCode(t, conn, "RCPT TO:<@route.example user@example.com>", "553")
// RCPT with valid TO arg should return 250 Ok
cmdCode(t, conn, "RCPT TO:<recipient@example.com>", "250")
@@ -821,6 +884,105 @@ func TestMakeEHLOResponse(t *testing.T) {
if !rePlain.MatchString(extensions["AUTH"]) {
t.Errorf("AUTH mechanism PLAIN does not appear in the extension list when an AuthHandler is specified and TLS is in use")
}
// 8BITMIME should always be advertised
s.srv = &Server{}
s.tls = false
extensions = parseExtensions(t, s.makeEHLOResponse())
if _, ok := extensions["8BITMIME"]; !ok {
t.Errorf("8BITMIME does not appear in the extension list")
}
// SMTPUTF8 should always be advertised
if _, ok := extensions["SMTPUTF8"]; !ok {
t.Errorf("SMTPUTF8 does not appear in the extension list")
}
// ENHANCEDSTATUSCODES should always be advertised
if _, ok := extensions["ENHANCEDSTATUSCODES"]; !ok {
t.Errorf("ENHANCEDSTATUSCODES does not appear in the extension list")
}
}
// Test 8BITMIME BODY parameter parsing in MAIL FROM command
func TestCmd8BITMIME(t *testing.T) {
srv := &Server{}
conn := newConn(t, srv)
cmdCode(t, conn, "EHLO host.example.com", "250")
// Create a session to check internal state
clientConn, serverConn := net.Pipe()
session := srv.newSession(serverConn)
go session.serve()
// Read and discard banner
_, _ = bufio.NewReader(clientConn).ReadString('\n')
// Send EHLO
_, _ = fmt.Fprintf(clientConn, "EHLO test.example.com\r\n")
reader := bufio.NewReader(clientConn)
for {
line, _ := reader.ReadString('\n')
if strings.HasPrefix(line, "250 ") {
break
}
}
// Test BODY=8BITMIME parameter
_, _ = fmt.Fprintf(clientConn, "MAIL FROM:<sender@example.com> BODY=8BITMIME\r\n")
resp, _ := reader.ReadString('\n')
if !strings.HasPrefix(resp, "250") {
t.Errorf("MAIL FROM with BODY=8BITMIME failed: %s", resp)
}
// Verify bodyEncoding was set (we can't directly access it, but we can test the behavior)
// Reset and test BODY=7BIT
_, _ = fmt.Fprintf(clientConn, "RSET\r\n")
_, _ = reader.ReadString('\n')
_, _ = fmt.Fprintf(clientConn, "MAIL FROM:<sender@example.com> BODY=7BIT\r\n")
resp, _ = reader.ReadString('\n')
if !strings.HasPrefix(resp, "250") {
t.Errorf("MAIL FROM with BODY=7BIT failed: %s", resp)
}
// Test BODY parameter with SIZE parameter
_, _ = fmt.Fprintf(clientConn, "RSET\r\n")
_, _ = reader.ReadString('\n')
_, _ = fmt.Fprintf(clientConn, "MAIL FROM:<sender@example.com> SIZE=1000 BODY=8BITMIME\r\n")
resp, _ = reader.ReadString('\n')
if !strings.HasPrefix(resp, "250") {
t.Errorf("MAIL FROM with SIZE and BODY parameters failed: %s", resp)
}
// Test case insensitivity
_, _ = fmt.Fprintf(clientConn, "RSET\r\n")
_, _ = reader.ReadString('\n')
_, _ = fmt.Fprintf(clientConn, "MAIL FROM:<sender@example.com> body=8bitmime\r\n")
resp, _ = reader.ReadString('\n')
if !strings.HasPrefix(resp, "250") {
t.Errorf("MAIL FROM with lowercase body parameter failed: %s", resp)
}
// Clean up
_, _ = fmt.Fprintf(clientConn, "QUIT\r\n")
_, _ = reader.ReadString('\n')
_ = clientConn.Close()
// Also test via the original connection
cmdCode(t, conn, "MAIL FROM:<sender@example.com> BODY=8BITMIME", "250")
cmdCode(t, conn, "RCPT TO:<recipient@example.com>", "250")
cmdCode(t, conn, "RSET", "250")
cmdCode(t, conn, "MAIL FROM:<sender@example.com> BODY=7BIT", "250")
cmdCode(t, conn, "RSET", "250")
cmdCode(t, conn, "MAIL FROM:<sender@example.com> BODY=8BITMIME SIZE=5000", "250")
cmdCode(t, conn, "QUIT", "221")
_ = conn.Close()
}
// func createTmpFile(content string) (file *os.File, err error) {
@@ -1598,3 +1760,172 @@ func TestCmdShutdown(t *testing.T) {
_ = conn.Close()
}
type mockDropRejectedHandler struct {
handlerCalled int
lastFrom string
lastTo []string
msgIDCalled int
lastMsgIDFrom string
lastMsgIDTo []string
}
func (m *mockDropRejectedHandler) handler(remoteAddr net.Addr, from string, to []string, data []byte) error {
m.handlerCalled++
m.lastFrom = from
m.lastTo = append([]string{}, to...) // copy slice
return nil
}
func (m *mockDropRejectedHandler) msgIDHandler(remoteAddr net.Addr, from string, to []string, data []byte, username *string) (string, error) {
m.msgIDCalled++
m.lastMsgIDFrom = from
m.lastMsgIDTo = append([]string{}, to...) // copy slice
return "test-message-id", nil
}
// Test the IgnoreRejectedRecipients option
func TestIgnoreRejectedRecipients(t *testing.T) {
tests := []struct {
name string
IgnoreRejectedRecipients bool
handlerRcpt func(net.Addr, string, string) bool
rcptCommands []struct{ addr, expectedCode string }
expectedHandlerCalls int
expectedHandlerRecipients []string
useMsgIDHandler bool
}{
{
name: "Disabled_DefaultBehavior",
IgnoreRejectedRecipients: false,
handlerRcpt: func(remoteAddr net.Addr, from string, to string) bool {
return !strings.HasSuffix(to, "@rejected.com")
},
rcptCommands: []struct{ addr, expectedCode string }{
{"valid@example.com", "250"},
{"invalid@rejected.com", "550"},
},
expectedHandlerCalls: 1,
expectedHandlerRecipients: []string{"valid@example.com"},
},
{
name: "Enabled_MixedRecipients",
IgnoreRejectedRecipients: true,
handlerRcpt: func(remoteAddr net.Addr, from string, to string) bool {
return !strings.HasSuffix(to, "@rejected.com")
},
rcptCommands: []struct{ addr, expectedCode string }{
{"valid1@example.com", "250"},
{"valid2@example.com", "250"},
{"invalid1@rejected.com", "250"}, // Now accepted but dropped
{"invalid2@rejected.com", "250"}, // Now accepted but dropped
},
expectedHandlerCalls: 1,
expectedHandlerRecipients: []string{"valid1@example.com", "valid2@example.com"},
},
{
name: "Enabled_AllRejected",
IgnoreRejectedRecipients: true,
handlerRcpt: func(remoteAddr net.Addr, from string, to string) bool {
return false // Reject all
},
rcptCommands: []struct{ addr, expectedCode string }{
{"test1@example.com", "250"}, // Accepted but dropped
{"test2@example.com", "250"}, // Accepted but dropped
},
expectedHandlerCalls: 0, // No handler calls since all rejected
expectedHandlerRecipients: nil,
},
{
name: "Enabled_OnlyValid",
IgnoreRejectedRecipients: true,
handlerRcpt: func(remoteAddr net.Addr, from string, to string) bool {
return strings.HasSuffix(to, "@valid.com")
},
rcptCommands: []struct{ addr, expectedCode string }{
{"user1@valid.com", "250"},
{"user2@valid.com", "250"},
{"user3@valid.com", "250"},
},
expectedHandlerCalls: 1,
expectedHandlerRecipients: []string{"user1@valid.com", "user2@valid.com", "user3@valid.com"},
},
{
name: "Enabled_WithMsgIDHandler",
IgnoreRejectedRecipients: true,
handlerRcpt: func(remoteAddr net.Addr, from string, to string) bool {
return !strings.HasSuffix(to, "@rejected.com")
},
rcptCommands: []struct{ addr, expectedCode string }{
{"valid@example.com", "250"},
{"invalid@rejected.com", "250"}, // Accepted but dropped
},
expectedHandlerCalls: 1,
expectedHandlerRecipients: []string{"valid@example.com"},
useMsgIDHandler: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mock := &mockDropRejectedHandler{}
server := &Server{
Hostname: "mail.example.com",
AppName: "TestMail",
MaxRecipients: 100,
HandlerRcpt: tt.handlerRcpt,
IgnoreRejectedRecipients: tt.IgnoreRejectedRecipients,
}
if tt.useMsgIDHandler {
server.MsgIDHandler = mock.msgIDHandler
} else {
server.Handler = mock.handler
}
conn := newConn(t, server)
defer func() { _ = conn.Close() }()
cmdCode(t, conn, "HELO host.example.com", "250")
cmdCode(t, conn, "MAIL FROM:<sender@example.com>", "250")
// Send RCPT commands
for _, rcpt := range tt.rcptCommands {
cmdCode(t, conn, "RCPT TO:<"+rcpt.addr+">", rcpt.expectedCode)
}
// Send DATA
cmdCode(t, conn, "DATA", "354")
cmdCode(t, conn, "Subject: Test\r\n\r\nTest message\r\n.", "250")
cmdCode(t, conn, "QUIT", "221")
// Verify handler calls
if tt.useMsgIDHandler {
if mock.msgIDCalled != tt.expectedHandlerCalls {
t.Errorf("Expected %d MsgIDHandler calls, got %d", tt.expectedHandlerCalls, mock.msgIDCalled)
}
if tt.expectedHandlerCalls > 0 {
if mock.lastMsgIDFrom != "sender@example.com" {
t.Errorf("Expected from 'sender@example.com', got '%s'", mock.lastMsgIDFrom)
}
if !reflect.DeepEqual(mock.lastMsgIDTo, tt.expectedHandlerRecipients) {
t.Errorf("Expected recipients %v, got %v", tt.expectedHandlerRecipients, mock.lastMsgIDTo)
}
}
} else {
if mock.handlerCalled != tt.expectedHandlerCalls {
t.Errorf("Expected %d handler calls, got %d", tt.expectedHandlerCalls, mock.handlerCalled)
}
if tt.expectedHandlerCalls > 0 {
if mock.lastFrom != "sender@example.com" {
t.Errorf("Expected from 'sender@example.com', got '%s'", mock.lastFrom)
}
if !reflect.DeepEqual(mock.lastTo, tt.expectedHandlerRecipients) {
t.Errorf("Expected recipients %v, got %v", tt.expectedHandlerRecipients, mock.lastTo)
}
}
}
})
}
}

View File

@@ -0,0 +1,196 @@
// Package snakeoil provides functionality to generate a temporary self-signed certificates
// for testing purposes. It generates a public and private key pair, stores them in the
// OS's temporary directory, returning the paths to these files.
package snakeoil
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64"
"encoding/pem"
"errors"
"math/big"
"os"
"strings"
"time"
"github.com/axllent/mailpit/internal/logger"
"github.com/axllent/mailpit/internal/tools"
)
var keys = make(map[string]KeyPair)
// KeyPair holds the public and private key paths for a self-signed certificate.
type KeyPair struct {
Public string
Private string
}
// Certificates returns all configured self-signed certificates in use,
// used for file deletion on exit.
func Certificates() map[string]KeyPair {
return keys
}
// Public returns the path to a generated PEM-encoded RSA public key.
func Public(str string) string {
domains, key, err := parse(str)
if err != nil {
logger.Log().Errorf("[tls] failed to parse domains: %v", err)
return ""
}
if pair, ok := keys[key]; ok {
return pair.Public
}
private, public, err := generate(domains)
if err != nil {
logger.Log().Errorf("[tls] failed to generate public certificate: %v", err)
return ""
}
keys[key] = KeyPair{
Public: public,
Private: private,
}
return public
}
// Private returns the path to a generated PEM-encoded RSA private key.
func Private(str string) string {
domains, key, err := parse(str)
if err != nil {
logger.Log().Errorf("[tls] failed to parse domains: %v", err)
return ""
}
if pair, ok := keys[key]; ok {
return pair.Private
}
private, public, err := generate(domains)
if err != nil {
logger.Log().Errorf("[tls] failed to generate public certificate: %v", err)
return ""
}
keys[key] = KeyPair{
Public: public,
Private: private,
}
return private
}
// Parse takes the original string input, removes the "sans:" prefix,
// splits the result into individual domains, and returns a slice of unique domains,
// along with a unique key that is a comma-separated list of these domains.
func parse(str string) ([]string, string, error) {
// remove "sans:" prefix
str = str[5:]
var domains []string
// split the string by commas and trim whitespace
for domain := range strings.SplitSeq(str, ",") {
domain = strings.ToLower(strings.TrimSpace(domain))
if domain != "" && !tools.InArray(domain, domains) {
domains = append(domains, domain)
}
}
if len(domains) == 0 {
return domains, "", errors.New("no valid domains provided")
}
// generate sha256 hash of the domains to create a unique key
hasher := sha256.New()
hasher.Write([]byte(strings.Join(domains, ",")))
key := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
return domains, key, nil
}
// Generate a new self-signed certificate and return a public & private key paths.
func generate(domains []string) (string, string, error) {
logger.Log().Infof("[tls] generating temp self-signed certificate for: %s", strings.Join(domains, ","))
key, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return "", "", err
}
keyBytes := x509.MarshalPKCS1PrivateKey(key)
// PEM encoding of private key
keyPEM := pem.EncodeToMemory(
&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: keyBytes,
},
)
notBefore := time.Now()
notAfter := notBefore.Add(365 * 24 * time.Hour)
// create certificate template
template := x509.Certificate{
SerialNumber: big.NewInt(0),
Subject: pkix.Name{
CommonName: domains[0],
Organization: []string{"Mailpit self-signed certificate"},
},
DNSNames: domains,
SignatureAlgorithm: x509.SHA256WithRSA,
NotBefore: notBefore,
NotAfter: notAfter,
BasicConstraintsValid: true,
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyAgreement | x509.KeyUsageKeyEncipherment | x509.KeyUsageDataEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
}
// create certificate using template
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
if err != nil {
return "", "", err
}
// PEM encoding of certificate
certPem := pem.EncodeToMemory(
&pem.Block{
Type: "CERTIFICATE",
Bytes: derBytes,
},
)
// Store the paths to the generated keys
priv, err := os.CreateTemp("", ".mailpit-*-private.pem")
if err != nil {
return "", "", err
}
if _, err := priv.Write(keyPEM); err != nil {
return "", "", err
}
if err := priv.Close(); err != nil {
return "", "", err
}
pub, err := os.CreateTemp("", ".mailpit-*-public.pem")
if err != nil {
return "", "", err
}
if _, err := pub.Write(certPem); err != nil {
return "", "", err
}
if err := pub.Close(); err != nil {
return "", "", err
}
return priv.Name(), pub.Name(), nil
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/axllent/mailpit/config"
"github.com/axllent/mailpit/internal/logger"
"github.com/axllent/mailpit/internal/storage"
"github.com/axllent/mailpit/internal/tools"
)
// Stores cached version along with its expiry time and error count.
@@ -81,7 +82,7 @@ func getBackoff(errCount int) time.Duration {
}
// Load the current statistics
func Load() AppInformation {
func Load(detectLatestVersion bool) AppInformation {
info := AppInformation{}
info.Version = config.Version
@@ -98,7 +99,7 @@ func Load() AppInformation {
if config.DisableVersionCheck {
info.LatestVersion = "disabled"
} else {
} else if detectLatestVersion {
mu.RLock()
cacheValid := time.Now().Before(vCache.expiry)
cacheValue := vCache.value
@@ -146,7 +147,7 @@ func Track() {
func LogSMTPAccepted(size int) {
mu.Lock()
smtpAccepted = smtpAccepted + 1
smtpAcceptedSize = smtpAcceptedSize + uint64(size)
smtpAcceptedSize = smtpAcceptedSize + tools.SafeUint64(size)
mu.Unlock()
}

View File

@@ -60,20 +60,19 @@ func pruneMessages() {
var size float64 // use float64 for rqlite compatibility
// prune using `--max` if set
if config.MaxMessages > 0 {
total := CountTotal()
if total > uint64(config.MaxAgeInHours) {
offset := config.MaxMessages
if config.DemoMode {
offset = 500
}
q := sqlf.Select("ID, Size").
From(tenant("mailbox")).
OrderBy("Created DESC").
Limit(5000).
Offset(offset)
if config.MaxMessages > 0 && CountTotal() > uint64(config.MaxMessages) {
offset := config.MaxMessages
if config.DemoMode {
offset = 500
}
q := sqlf.Select("ID, Size").
From(tenant("mailbox")).
OrderBy("Created DESC").
Limit(5000).
Offset(offset)
if err := q.QueryAndClose(context.TODO(), db, func(row *sql.Rows) {
if err := q.QueryAndClose(
context.TODO(), db, func(row *sql.Rows) {
var id string
if err := row.Scan(&id, &size); err != nil {
@@ -83,10 +82,10 @@ func pruneMessages() {
ids = append(ids, id)
prunedSize = prunedSize + uint64(size)
}); err != nil {
logger.Log().Errorf("[db] %s", err.Error())
return
}
},
); err != nil {
logger.Log().Errorf("[db] %s", err.Error())
return
}
}

View File

@@ -3,6 +3,9 @@ package storage
import (
"bytes"
"context"
"crypto/md5" // #nosec
"crypto/sha1" // #nosec
"crypto/sha256"
"database/sql"
"encoding/base64"
"encoding/hex"
@@ -108,7 +111,7 @@ func Store(body *[]byte, username *string) (string, error) {
if config.Compression > 0 {
// insert compressed raw message
compressed := dbEncoder.EncodeAll(*body, make([]byte, 0, int(size)))
compressed := dbEncoder.EncodeAll(*body, make([]byte, 0, size))
if sqlDriver == "rqlite" {
// rqlite does not support binary data in query, so we need to encode the compressed message into hexadecimal
@@ -202,7 +205,7 @@ func Store(body *[]byte, username *string) (string, error) {
BroadcastMailboxStats()
logger.Log().Debugf("[db] saved message %s (%d bytes)", id, int64(size))
logger.Log().Debugf("[db] saved message %s (%d bytes)", id, size)
return id, nil
}
@@ -505,6 +508,14 @@ func AttachmentSummary(a *enmime.Part) Attachment {
o.ContentID = a.ContentID
o.Size = uint64(len(a.Content))
md5Hash := md5.Sum(a.Content) // #nosec
sha1Hash := sha1.Sum(a.Content) // #nosec
sha256Hash := sha256.Sum256(a.Content)
o.Checksums.MD5 = hex.EncodeToString(md5Hash[:])
o.Checksums.SHA1 = hex.EncodeToString(sha1Hash[:])
o.Checksums.SHA256 = hex.EncodeToString(sha256Hash[:])
return o
}

View File

@@ -1,6 +1,7 @@
package storage
import (
"os"
"testing"
"time"
@@ -204,3 +205,99 @@ func BenchmarkImportMime(b *testing.B) {
}
}
func TestInlineImageContentIdHandling(t *testing.T) {
setup("")
defer Close()
t.Log("Testing inline content handling")
// Test case: Proper inline image with Content-Disposition: inline
inlineAttachment, err := os.ReadFile("testdata/inline-attachment.eml")
if err != nil {
t.Fatalf("Failed to read test email: %v", err)
}
storedMessage, err := Store(&inlineAttachment, nil)
if err != nil {
t.Fatal("Failed to store test case 1:", err)
}
msg, err := GetMessage(storedMessage)
if err != nil {
t.Fatal("Failed to retrieve test case 1:", err)
}
// Assert
if len(msg.Inline) != 1 {
t.Errorf("Test case 1: Expected 1 inline attachment, got %d", len(msg.Inline))
}
if len(msg.Attachments) != 0 {
t.Errorf("Test case 1: Expected 0 regular attachments, got %d", len(msg.Attachments))
}
if msg.Inline[0].ContentID != "test1@example.com" {
t.Errorf("Test case 1: Expected ContentID 'test1@example.com', got '%s'", msg.Inline[0].ContentID)
}
}
func TestRegularAttachmentHandling(t *testing.T) {
setup("")
defer Close()
t.Log("Testing regular attachment handling")
// Test case: Regular attachment without Content-ID
regularAttachment, err := os.ReadFile("testdata/regular-attachment.eml")
if err != nil {
t.Fatalf("Failed to read test email: %v", err)
}
storedMessage, err := Store(&regularAttachment, nil)
if err != nil {
t.Fatal("Failed to store test case 3:", err)
}
msg, err := GetMessage(storedMessage)
if err != nil {
t.Fatal("Failed to retrieve test case 3:", err)
}
// Assert
if len(msg.Inline) != 0 {
t.Errorf("Test case 3: Expected 0 inline attachments, got %d", len(msg.Inline))
}
if len(msg.Attachments) != 1 {
t.Errorf("Test case 3: Expected 1 regular attachment, got %d", len(msg.Attachments))
}
if msg.Attachments[0].ContentID != "" {
t.Errorf("Test case 3: Expected empty ContentID, got '%s'", msg.Attachments[0].ContentID)
}
// Checksum tests
assertEqual(t, msg.Attachments[0].Checksums.MD5, "b04930eb1ba0c62066adfa87e5d262c4", "Attachment MD5 checksum does not match")
assertEqual(t, msg.Attachments[0].Checksums.SHA1, "15605d6a2fca44e966209d1701f16ecf816df880", "Attachment SHA1 checksum does not match")
assertEqual(t, msg.Attachments[0].Checksums.SHA256, "92c4ccff376003381bd9054d3da7b32a3c5661905b55e3b0728c17aba6d223ec", "Attachment SHA256 checksum does not match")
}
func TestMixedAttachmentHandling(t *testing.T) {
setup("")
defer Close()
t.Log("Testing mixed attachment handling")
// Mixed scenario with both inline and regular attachment
mixedAttachment, err := os.ReadFile("testdata/mixed-attachment.eml")
if err != nil {
t.Fatalf("Failed to read test email: %v", err)
}
storedMessage, err := Store(&mixedAttachment, nil)
if err != nil {
t.Fatal("Failed to store test case 4:", err)
}
msg, err := GetMessage(storedMessage)
if err != nil {
t.Fatal("Failed to retrieve test case 4:", err)
}
// Assert: Should have 1 inline (with ContentID) and 1 attachment (without ContentID)
if len(msg.Inline) != 1 {
t.Errorf("Test case 4: Expected 1 inline attachment, got %d", len(msg.Inline))
}
if len(msg.Attachments) != 1 {
t.Errorf("Test case 4: Expected 1 regular attachment, got %d", len(msg.Attachments))
}
if msg.Inline[0].ContentID != "inline@example.com" {
t.Errorf("Test case 4: Expected inline ContentID 'inline@example.com', got '%s'", msg.Inline[0].ContentID)
}
if msg.Attachments[0].ContentID != "" {
t.Errorf("Test case 4: Expected attachment ContentID to be empty, got '%s'", msg.Attachments[0].ContentID)
}
}

View File

@@ -27,7 +27,7 @@ func ReindexAll() {
err := sqlf.Select("ID").To(&i).
From(tenant("mailbox")).
OrderBy("Created DESC").
QueryAndClose(context.TODO(), db, func(row *sql.Rows) {
QueryAndClose(context.TODO(), db, func(_ *sql.Rows) {
ids = append(ids, i)
})

View File

@@ -15,7 +15,7 @@ func SettingGet(k string) string {
Select("Value").To(&result).
Where("Key = ?", k).
Limit(1).
QueryAndClose(context.TODO(), db, func(row *sql.Rows) {})
QueryAndClose(context.TODO(), db, func(_ *sql.Rows) {})
if err != nil {
logger.Log().Errorf("[db] %s", err.Error())
return ""
@@ -41,7 +41,7 @@ func getDeletedSize() uint64 {
Select("Value").To(&result).
Where("Key = ?", "DeletedSize").
Limit(1).
QueryAndClose(context.TODO(), db, func(row *sql.Rows) {})
QueryAndClose(context.TODO(), db, func(_ *sql.Rows) {})
if err != nil {
logger.Log().Errorf("[db] %s", err.Error())
return 0
@@ -55,7 +55,7 @@ func totalMessagesSize() uint64 {
var result sql.NullFloat64
err := sqlf.From(tenant("mailbox")).
Select("SUM(Size)").To(&result).
QueryAndClose(context.TODO(), db, func(row *sql.Rows) {})
QueryAndClose(context.TODO(), db, func(_ *sql.Rows) {})
if err != nil {
logger.Log().Errorf("[db] %s", err.Error())
return 0

View File

@@ -48,7 +48,7 @@ type Message struct {
Attachments []Attachment
}
// Attachment struct for inline and attachments
// Attachment struct for inline images and attachments
//
// swagger:model Attachment
type Attachment struct {
@@ -62,6 +62,15 @@ type Attachment struct {
ContentID string
// Size in bytes
Size uint64
// File checksums
Checksums struct {
// MD5 checksum hash of file
MD5 string
// SHA1 checksum hash of file
SHA1 string
// SHA256 checksum hash of file
SHA256 string
}
}
// MessageSummary struct for frontend messages

View File

@@ -147,7 +147,7 @@ func GetAllTags() []string {
Select(`DISTINCT Name`).
From(tenant("tags")).To(&name).
OrderBy("Name").
QueryAndClose(context.TODO(), db, func(row *sql.Rows) {
QueryAndClose(context.TODO(), db, func(_ *sql.Rows) {
tags = append(tags, name)
}); err != nil {
logger.Log().Errorf("[db] %s", err.Error())
@@ -169,7 +169,7 @@ func GetAllTagsCount() map[string]int64 {
LeftJoin(tenant("message_tags"), tenant("tags.ID")+" = "+tenant("message_tags.TagID")).
GroupBy(tenant("message_tags.TagID")).
OrderBy("Name").
QueryAndClose(context.TODO(), db, func(row *sql.Rows) {
QueryAndClose(context.TODO(), db, func(_ *sql.Rows) {
tags[name] = int64(total)
}); err != nil {
logger.Log().Errorf("[db] %s", err.Error())
@@ -352,7 +352,7 @@ func getMessageTags(id string) []string {
LeftJoin(tenant("message_tags"), tenant("Tags.ID")+"="+tenant("message_tags.TagID")).
Where(tenant("message_tags.ID")+` = ?`, id).
OrderBy("Name").
QueryAndClose(context.TODO(), db, func(row *sql.Rows) {
QueryAndClose(context.TODO(), db, func(_ *sql.Rows) {
tags = append(tags, name)
}); err != nil {
logger.Log().Errorf("[tags] %s", err.Error())

View File

@@ -0,0 +1,20 @@
From: sender@example.com
To: recipient@example.com
Subject: Test inline image proper
MIME-Version: 1.0
Content-Type: multipart/related; boundary="boundary123"
--boundary123
Content-Type: text/html; charset=utf-8
<html><body><img src="cid:test1@example.com" alt="Test"/></body></html>
--boundary123
Content-Type: image/png; name="test1.png"
Content-Disposition: inline; filename="test1.png"
Content-ID: <test1@example.com>
Content-Transfer-Encoding: base64
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==
--boundary123--

View File

@@ -0,0 +1,27 @@
From: sender@example.com
To: recipient@example.com
Subject: Test mixed attachments
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="boundary111"
--boundary111
Content-Type: text/html; charset=utf-8
<html><body><img src="cid:inline@example.com" alt="Inline"/><p>Document attached</p></body></html>
--boundary111
Content-Type: image/png; name="inline.png"
Content-Disposition: inline; filename="inline.png"
Content-ID: <inline@example.com>
Content-Transfer-Encoding: base64
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==
--boundary111
Content-Type: application/pdf; name="document.pdf"
Content-Disposition: attachment; filename="document.pdf"
Content-Transfer-Encoding: base64
JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9GbGF0ZURlY29kZT4+CnN0cmVhbQo=
--boundary111--

View File

@@ -0,0 +1,19 @@
From: sender@example.com
To: recipient@example.com
Subject: Test regular attachment
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="boundary789"
--boundary789
Content-Type: text/html; charset=utf-8
<html><body><p>Message with regular attachment</p></body></html>
--boundary789
Content-Type: application/pdf; name="document.pdf"
Content-Disposition: attachment; filename="document.pdf"
Content-Transfer-Encoding: base64
JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9GbGF0ZURlY29kZT4+CnN0cmVhbQo=
--boundary789--

View File

@@ -9,6 +9,7 @@ import (
"github.com/axllent/mailpit/internal/html2text"
"github.com/axllent/mailpit/internal/logger"
"github.com/axllent/mailpit/internal/tools"
"github.com/jhillyerd/enmime/v2"
)
@@ -88,7 +89,7 @@ func cleanString(str string) string {
// LogMessagesDeleted logs the number of messages deleted
func logMessagesDeleted(n int) {
mu.Lock()
StatsDeleted = StatsDeleted + uint64(n)
StatsDeleted = StatsDeleted + tools.SafeUint64(n)
mu.Unlock()
}

28
internal/tools/net.go Normal file
View File

@@ -0,0 +1,28 @@
package tools
import (
"net"
"net/url"
)
// IsInternalIP checks if the given IP address is an internal IP address (e.g., loopback, private, link-local, or multicast).
// IsLoopback — 127.0.0.0/8, ::1
// IsPrivate — 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7
// IsLinkLocalUnicast — 169.254.0.0/16, fe80::/10 (covers cloud metadata 169.254.169.254)
// IsLinkLocalMulticast — 224.0.0.0/24, ff02::/16
// IsUnspecified — 0.0.0.0, ::
// IsMulticast — 224.0.0.0/4, ff00::/8
func IsInternalIP(ip net.IP) bool {
return ip.IsLoopback() ||
ip.IsPrivate() ||
ip.IsLinkLocalUnicast() ||
ip.IsLinkLocalMulticast() ||
ip.IsUnspecified() ||
ip.IsMulticast()
}
// IsValidLinkURL checks if the provided string is a valid URL with http or https scheme and a non-empty hostname.
func IsValidLinkURL(str string) bool {
u, err := url.Parse(str)
return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Hostname() != ""
}

View File

@@ -10,7 +10,7 @@ import (
var (
// Invalid tag characters regex
tagsInvalidChars = regexp.MustCompile(`[^a-zA-Z0-9\-\ \_\.]`)
tagsInvalidChars = regexp.MustCompile(`[^a-zA-Z0-9\-\ \_\.@]`)
// Regex to catch multiple spaces
multiSpaceRe = regexp.MustCompile(`(\s+)`)
@@ -19,14 +19,21 @@ var (
TagsTitleCase bool
)
// CleanTag returns a clean tag, trimming whitespace and replacing invalid characters
// CleanTag returns a clean tag, trimming whitespace and replacing invalid characters.
// If the tag is longer than 100 characters, it is truncated.
func CleanTag(s string) string {
return strings.TrimSpace(
t := strings.TrimSpace(
multiSpaceRe.ReplaceAllString(
tagsInvalidChars.ReplaceAllString(s, " "),
" ",
),
)
if len(t) > 100 {
return t[:100]
}
return t
}
// SetTagCasing returns the slice of tags, title-casing if set

View File

@@ -33,7 +33,8 @@ func TestCleanTag(t *testing.T) {
tests["thiS IS a Test :-)"] = "thiS IS a Test -"
tests[" thiS 99 IS a Test :-)"] = "thiS 99 IS a Test -"
tests["this_is-a test "] = "this_is-a test"
tests["this_is-a&^%%(*)@ test"] = "this_is-a test"
tests["this_is-a&^%%(*)@ test"] = "this_is-a @ test"
tests["this is a long tag title with more than 100 characters, which should get automatically truncated to 100 characters"] = "this is a long tag title with more than 100 characters which should get automatically truncated to 1"
for search, expected := range tests {
res := CleanTag(search)

View File

@@ -36,3 +36,22 @@ func Normalize(s string) string {
return strings.TrimSpace(s)
}
// SafeUint64 converts an int or int64 to uint64, ensuring it does not exceed the maximum value for uint64.
func SafeUint64(i any) uint64 {
switch v := i.(type) {
case int:
if v < 0 {
return 0
}
return uint64(v)
case int64:
if v < 0 {
return 0
}
return uint64(v)
default:
// only accepts int or int64
return 0
}
}

5043
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@
"lint-fix": "eslint --fix && prettier --write ."
},
"dependencies": {
"axios": "^1.2.1",
"axios": "^1.13.5",
"bootstrap": "^5.2.0",
"bootstrap-icons": "^1.9.1",
"bootstrap5-tags": "^1.6.1",
@@ -30,20 +30,22 @@
"vue-router": "^4.2.4"
},
"devDependencies": {
"@eslint/compat": "^2.0.2",
"@eslint/js": "^10.0.1",
"@popperjs/core": "^2.11.5",
"@types/bootstrap": "^5.2.7",
"@types/tinycon": "^0.6.3",
"@vue/compiler-sfc": "^3.2.37",
"esbuild": "^0.25.0",
"esbuild": "^0.27.2",
"esbuild-plugin-vue-next": "^0.1.4",
"esbuild-sass-plugin": "^3.0.0",
"eslint": "^9.29.0",
"eslint": "^10.0.1",
"eslint-config-prettier": "^10.1.5",
"eslint-plugin-vue": "^10.2.0",
"neostandard": "^0.12.1",
"globals": "^17.3.0",
"prettier": "^3.5.3"
},
"prettier":{
"prettier": {
"tabWidth": 4,
"useTabs": true,
"printWidth": 120

View File

@@ -2,11 +2,14 @@
package cmd
import (
"crypto/tls"
"errors"
"fmt"
"net"
"net/mail"
"net/smtp"
"os"
"strings"
"github.com/axllent/mailpit/internal/logger"
)
@@ -27,7 +30,7 @@ func Send(addr string, from string, to []string, msg []byte) error {
}
if !isSocket {
return smtp.SendMail(addr, nil, fromAddress.Address, to, msg)
return sendMail(addr, nil, fromAddress.Address, to, msg)
}
conn, err := net.Dial("unix", socketPath)
@@ -69,3 +72,76 @@ func Send(addr string, from string, to []string, msg []byte) error {
return nil
}
func sendMail(addr string, a smtp.Auth, from string, to []string, msg []byte) error {
if err := validateLine(from); err != nil {
return err
}
for _, recipient := range to {
if err := validateLine(recipient); err != nil {
return err
}
}
c, err := smtp.Dial(addr)
if err != nil {
return err
}
defer func() { _ = c.Close() }()
if err = c.Hello(addr); err != nil {
return err
}
if ok, _ := c.Extension("STARTTLS"); ok {
config := &tls.Config{ServerName: addr, InsecureSkipVerify: true} // #nosec
if err = c.StartTLS(config); err != nil {
return err
}
}
if a != nil {
if ok, _ := c.Extension("AUTH"); !ok {
return errors.New("smtp: server doesn't support AUTH")
}
if err = c.Auth(a); err != nil {
return err
}
}
if err = c.Mail(from); err != nil {
return err
}
for _, addr := range to {
if err = c.Rcpt(addr); err != nil {
return err
}
}
w, err := c.Data()
if err != nil {
return err
}
_, err = w.Write(msg)
if err != nil {
return err
}
err = w.Close()
if err != nil {
return err
}
return c.Quit()
}
// validateLine checks to see if a line has CR or LF as per RFC 5321.
func validateLine(line string) error {
if strings.ContainsAny(line, "\n\r") {
return errors.New("smtp: A line must not contain CR or LF")
}
return nil
}

View File

@@ -28,7 +28,7 @@ func AppInfo(w http.ResponseWriter, _ *http.Request) {
// 400: ErrorResponse
w.Header().Add("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(stats.Load()); err != nil {
if err := json.NewEncoder(w).Encode(stats.Load(true)); err != nil {
httpError(w, err.Error())
}
}

View File

@@ -6,6 +6,7 @@ import (
"strings"
"github.com/axllent/mailpit/internal/storage"
"github.com/axllent/mailpit/internal/tools"
)
// MessagesSummary is a summary of a list of messages
@@ -241,9 +242,9 @@ func Search(w http.ResponseWriter, r *http.Request) {
res.Start = start
res.Messages = messages
res.Count = uint64(len(messages)) // legacy - now undocumented in API specs
res.Total = stats.Total // total messages in mailbox
res.MessagesCount = uint64(results)
res.Count = tools.SafeUint64(len(messages)) // legacy - now undocumented in API specs
res.Total = stats.Total // total messages in mailbox
res.MessagesCount = tools.SafeUint64(results)
res.Unread = stats.Unread
res.Tags = stats.Tags
@@ -253,7 +254,7 @@ func Search(w http.ResponseWriter, r *http.Request) {
return
}
res.MessagesUnreadCount = uint64(unread)
res.MessagesUnreadCount = tools.SafeUint64(unread)
w.Header().Add("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(res); err != nil {

View File

@@ -76,13 +76,14 @@ func Thumbnail(w http.ResponseWriter, r *http.Request) {
var b bytes.Buffer
foo := bufio.NewWriter(&b)
var dstImageFill *image.NRGBA
var temp image.Image
if img.Bounds().Dx() < thumbWidth || img.Bounds().Dy() < thumbHeight {
dstImageFill = imaging.Fit(img, thumbWidth, thumbHeight, imaging.Lanczos)
temp = imaging.Fit(img, thumbWidth, thumbHeight, imaging.Lanczos)
} else {
dstImageFill = imaging.Fill(img, thumbWidth, thumbHeight, imaging.Center, imaging.Lanczos)
temp = imaging.Fill(img, thumbWidth, thumbHeight, imaging.Center, imaging.Lanczos)
}
dstImageFill := imaging.Clone(temp)
// create white image and paste image over the top
// preventing black backgrounds for transparent GIF/PNG images
dst := imaging.New(thumbWidth, thumbHeight, color.White)

130
server/cors.go Normal file
View File

@@ -0,0 +1,130 @@
package server
import (
"net/http"
"net/url"
"sort"
"strings"
"github.com/axllent/mailpit/internal/logger"
)
var (
// AccessControlAllowOrigin CORS policy - set with flags/env
AccessControlAllowOrigin string
// CorsAllowOrigins are optional allowed origins by hostname, set via setCORSOrigins().
corsAllowOrigins = make(map[string]bool)
)
// equalASCIIFold reports whether s and t, interpreted as UTF-8 strings, are equal
// under Unicode case folding, ignoring any difference in length.
func asciiFoldString(s string) string {
b := make([]byte, len(s))
for i := range s {
b[i] = toLowerASCIIFold(s[i])
}
return string(b)
}
// toLowerASCIIFold returns the Unicode case-folded equivalent of the ASCII character c.
// It is equivalent to the Unicode 13.0.0 function foldCase(c, CaseFoldingMapping).
func toLowerASCIIFold(c byte) byte {
if 'A' <= c && c <= 'Z' {
return c + 'a' - 'A'
}
return c
}
// CorsOriginAccessControl checks if the request origin is allowed based on the configured CORS origins.
func corsOriginAccessControl(r *http.Request) bool {
origin := r.Header["Origin"]
if len(origin) != 0 {
u, err := url.Parse(origin[0])
if err != nil {
logger.Log().Errorf("[cors] origin parse error: %v", err)
return false
}
_, allAllowed := corsAllowOrigins["*"]
// allow same origin || is "*" is defined as an origin
if asciiFoldString(u.Host) == asciiFoldString(r.Host) || allAllowed {
return true
}
originHostFold := asciiFoldString(u.Hostname())
if corsAllowOrigins[originHostFold] {
return true
}
logger.Log().Warnf("[cors] blocking request from unauthorized origin: %s", u.Hostname())
return false
}
return true
}
// SetCORSOrigins sets the allowed CORS origins from a comma-separated string.
// It does not consider port or protocol, only the hostname.
func setCORSOrigins() {
corsAllowOrigins = make(map[string]bool)
hosts := extractOrigins(AccessControlAllowOrigin)
for _, host := range hosts {
corsAllowOrigins[asciiFoldString(host)] = true
}
if _, wildCard := corsAllowOrigins["*"]; wildCard {
// reset to just wildcard
corsAllowOrigins = make(map[string]bool)
corsAllowOrigins["*"] = true
logger.Log().Info("[cors] all origins are allowed due to wildcard \"*\"")
} else {
keys := make([]string, 0)
for k := range corsAllowOrigins {
keys = append(keys, k)
}
sort.Strings(keys)
logger.Log().Infof("[cors] allowed API origins: %v", strings.Join(keys, ", "))
}
}
// extractOrigins extracts and returns a sorted list of origins from a comma-separated string.
func extractOrigins(str string) []string {
origins := make([]string, 0)
s := strings.TrimSpace(str)
if s == "" {
return origins
}
hosts := strings.FieldsFunc(s, func(r rune) bool {
return r == ',' || r == ' '
})
for _, host := range hosts {
h := strings.TrimSpace(host)
if h != "" {
if h == "*" {
return []string{"*"}
}
if !strings.HasPrefix(h, "http://") && !strings.HasPrefix(h, "https://") {
h = "http://" + h
}
u, err := url.Parse(h)
if err != nil || u.Hostname() == "" || strings.Contains(h, "*") {
logger.Log().Warnf("[cors] invalid CORS origin \"%s\", ignoring", h)
continue
}
origins = append(origins, u.Hostname())
}
}
sort.Strings(origins)
return origins
}

119
server/cors_test.go Normal file
View File

@@ -0,0 +1,119 @@
package server
import (
"net/http"
"testing"
)
func TestExtractOrigins(t *testing.T) {
tests := []struct {
name string
input string
expected []string
}{
{
name: "empty string",
input: "",
expected: []string{},
},
{
name: "single hostname",
input: "example.com",
expected: []string{"example.com"},
},
{
name: "multiple hostnames comma separated",
input: "example.com,foo.com",
expected: []string{"example.com", "foo.com"},
},
{
name: "multiple hostnames space separated",
input: "example.com foo.com",
expected: []string{"example.com", "foo.com"},
},
{
name: "wildcard",
input: "*",
expected: []string{"*"},
},
{
name: "mixed protocols",
input: "http://example.com,https://foo.com:8080",
expected: []string{"example.com", "foo.com"},
},
{
name: "embedded wildcard",
input: "http://example.com,*,https://test",
expected: []string{"*"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := extractOrigins(tt.input)
if len(got) != len(tt.expected) {
t.Errorf("expected %d origins, got %d", len(tt.expected), len(got))
return
}
for i := range got {
if got[i] != tt.expected[i] {
t.Errorf("expected origin %q, got %q", tt.expected[i], got[i])
}
}
})
}
}
func TestCorsOriginAccessControl(t *testing.T) {
// Setup allowed origins
AccessControlAllowOrigin = "example.com,foo.com,bar.com"
setCORSOrigins()
tests := []struct {
name string
origin string
host string
allow bool
}{
{"no origin header", "", "example.com", true},
{"allowed origin", "http://example.com:1234", "mailpit.local", true},
{"not allowed origin", "http://notallowed.com", "mailpit.local", false},
{"allowed by hostname", "http://foo.com", "mailpit.local", true},
{"ascii fold: allowed origin uppercase", "HTTP://EXAMPLE.COM", "mailpit.local", true},
{"ascii fold: allowed by hostname uppercase", "HTTP://FOO.COM", "mailpit.local", true},
{"ascii fold: host uppercase", "http://example.com", "MAILPIT.LOCAL", true},
{"ascii fold: not allowed origin uppercase", "HTTP://NOTALLOWED.COM", "mailpit.local", false},
{"ascii fold: mixed case", "HtTp://ExAmPlE.CoM", "mailpit.local", true},
{"non-ascii: allowed origin (unicode hostname)", "http://exámple.com", "mailpit.local", false},
{"non-ascii: allowed by hostname (unicode)", "http://föö.com", "mailpit.local", false},
{"non-ascii: host uppercase (unicode)", "http://exámple.com", "MAILPIT.LOCAL", false},
{"non-ascii: mixed case (unicode)", "HtTp://ExÁmPlE.CoM", "mailpit.local", false},
}
// Add wildcard test
AccessControlAllowOrigin = "*"
setCORSOrigins()
reqWildcard := &http.Request{Header: http.Header{"Origin": {"http://any.com"}}, Host: "mailpit.local"}
if !corsOriginAccessControl(reqWildcard) {
t.Error("Wildcard origin should be allowed")
}
// Reset to specific hosts
AccessControlAllowOrigin = "example.com,foo.com,bar.com"
setCORSOrigins()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := &http.Request{Header: http.Header{}, Host: tt.host}
if tt.origin != "" {
req.Header.Set("Origin", tt.origin)
}
allowed := corsOriginAccessControl(req)
if allowed != tt.allow {
t.Errorf("expected allowed=%v, got %v for origin=%q host=%q", tt.allow, allowed, tt.origin, tt.host)
}
})
}
}

View File

@@ -2,51 +2,140 @@
package handlers
import (
"context"
"crypto/tls"
"encoding/base64"
"errors"
"fmt"
"io"
"net"
"net/http"
"net/url"
"regexp"
"strings"
"sync"
"time"
"github.com/PuerkitoBio/goquery"
"github.com/axllent/mailpit/config"
"github.com/axllent/mailpit/internal/logger"
"github.com/axllent/mailpit/internal/storage"
"github.com/axllent/mailpit/internal/tools"
)
var linkRe = regexp.MustCompile(`(?i)^https?:\/\/`)
var (
linkRe = regexp.MustCompile(`(?i)^https?:\/\/`)
// ProxyHandler is used to proxy assets for printing
urlRe = regexp.MustCompile(`(?mU)url\(('|")?(https?:\/\/[^)'"]+)('|")?\)`)
assetsMutex sync.Mutex
assets = map[string]MessageAssets{}
)
// MessageAssets represents assets linked in a message
type MessageAssets struct {
ID string
// Created timestamp so we can expire old entries
Created time.Time
// Assets found in the message
Assets []string
}
func init() {
// Start a goroutine to clean up old asset entries every minute
go func() {
for {
time.Sleep(time.Minute)
assetsMutex.Lock()
now := time.Now()
for id, entry := range assets {
if now.Sub(entry.Created) > time.Minute {
logger.Log().Debugf("[proxy] cleaning up assets for message %s", id)
delete(assets, id)
}
}
assetsMutex.Unlock()
}
}()
}
// ProxyHandler is used to proxy assets for printing.
// It accepts a base64-encoded message-id:url string as the `data` query parameter.
func ProxyHandler(w http.ResponseWriter, r *http.Request) {
uri := strings.TrimSpace(r.URL.Query().Get("url"))
if uri == "" {
logger.Log().Warn("[proxy] URL missing")
httpError(w, "Error: URL missing")
encoded := strings.TrimSpace(r.URL.Query().Get("data"))
if encoded == "" {
logger.Log().Warn("[proxy] Data missing")
httpError(w, "Error: Data missing")
return
}
if !linkRe.MatchString(uri) {
decoded, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
logger.Log().Warnf("[proxy] Data parameter corrupted: %s", err.Error())
httpError(w, "Error: invalid request")
return
}
parts := strings.SplitN(string(decoded), ":", 2)
if len(parts) != 2 {
logger.Log().Warnf("[proxy] Invalid data parameter: %s", string(decoded))
httpError(w, "Error: invalid request")
return
}
id := parts[0]
uri := parts[1]
links, err := getAssets(id)
if err != nil {
httpError(w, "Error: invalid request")
return
}
if !tools.InArray(uri, links) {
logger.Log().Warnf("[proxy] URL %s not found in message %s", uri, id)
httpError(w, "Error: invalid request")
return
}
if !linkRe.MatchString(uri) || !tools.IsValidLinkURL(uri) {
logger.Log().Warnf("[proxy] invalid URL %s", uri)
httpError(w, "Error: invalid URL")
return
}
tr := &http.Transport{}
dialer := &net.Dialer{
Timeout: 10 * time.Second,
KeepAlive: 30 * time.Second,
}
tr := &http.Transport{
DialContext: safeDialContext(dialer),
}
if config.AllowUntrustedTLS {
tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} // #nosec
}
client := &http.Client{
Transport: tr,
Timeout: 10 * time.Second,
Transport: tr,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
if len(via) >= 3 {
return errors.New("too many redirects")
}
if !tools.IsValidLinkURL(req.URL.String()) {
return fmt.Errorf("blocked redirect to invalid URL: %s", req.URL)
}
return nil
},
}
req, err := http.NewRequest("GET", uri, nil)
if err != nil {
logger.Log().Warnf("[proxy] %s", err.Error())
httpError(w, err.Error())
httpError(w, "Error: invalid request")
return
}
@@ -56,23 +145,34 @@ func ProxyHandler(w http.ResponseWriter, r *http.Request) {
resp, err := client.Do(req)
if err != nil {
logger.Log().Warnf("[proxy] %s", err.Error())
httpError(w, err.Error())
httpError(w, "Error: invalid request")
return
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
logger.Log().Warnf("[proxy] received status code %d for %s", resp.StatusCode, uri)
httpError(w, "Error: invalid request")
return
}
ct := strings.ToLower(resp.Header.Get("content-type"))
if !supportedProxyContentType(ct) {
logger.Log().Warnf("[proxy] blocking unsupported content-type %s for %s", ct, uri)
httpError(w, "Error: invalid request")
return
}
body, err := io.ReadAll(resp.Body)
if err != nil {
logger.Log().Warnf("[proxy] %s", err.Error())
httpError(w, err.Error())
httpError(w, "Error: invalid request")
return
}
// relay common headers
if resp.Header.Get("content-type") != "" {
w.Header().Set("content-type", resp.Header.Get("content-type"))
}
w.Header().Set("content-type", ct)
if resp.Header.Get("last-modified") != "" {
w.Header().Set("last-modified", resp.Header.Get("last-modified"))
}
@@ -83,7 +183,7 @@ func ProxyHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("cache-control", resp.Header.Get("cache-control"))
}
// replace url() values with proxy address, eg: fonts & images
// replace CSS url() values with proxy address, eg: fonts & images
if strings.HasPrefix(resp.Header.Get("content-type"), "text/css") {
var re = regexp.MustCompile(`(?mi)(url\((\'|\")?([^\)\'\"]+)(\'|\")?\))`)
body = re.ReplaceAllFunc(body, func(s []byte) []byte {
@@ -100,7 +200,20 @@ func ProxyHandler(w http.ResponseWriter, r *http.Request) {
return []byte(parts[3])
}
return []byte("url(" + parts[2] + config.Webroot + "proxy?url=" + url.QueryEscape(address) + parts[4] + ")")
// store asset address against message ID
if result, ok := assets[id]; ok {
if !tools.InArray(address, result.Assets) {
assetsMutex.Lock()
result.Assets = append(result.Assets, address)
assets[id] = result
assetsMutex.Unlock()
}
}
// encode with base64 to handle any special characters and group message ID with URL
encoded := base64.StdEncoding.EncodeToString([]byte(id + ":" + address))
return []byte("url(" + parts[2] + config.Webroot + "proxy?data=" + encoded + parts[4] + ")")
})
}
@@ -114,7 +227,82 @@ func ProxyHandler(w http.ResponseWriter, r *http.Request) {
}
}
// AbsoluteURL will return a full URL regardless whether it is relative or absolute
// GetAssets retrieves and parses the message to return linked assets.
// Linked CSS files are appended to the assets list via the ProxyHandler when proxying CSS files.
func getAssets(id string) ([]string, error) {
assetsMutex.Lock()
defer assetsMutex.Unlock()
result, ok := assets[id]
if ok {
// return cached assets
return result.Assets, nil
}
msg, err := storage.GetMessage(id)
if err != nil {
return nil, err
}
links := []string{}
reader := strings.NewReader(msg.HTML)
// load the HTML document
doc, err := goquery.NewDocumentFromReader(reader)
if err != nil {
return nil, err
}
// css & font links
doc.Find("link").Each(func(_ int, s *goquery.Selection) {
if href, exists := s.Attr("href"); exists {
if linkRe.MatchString(href) && !tools.InArray(href, links) {
links = append(links, href)
}
}
})
// images
doc.Find("img").Each(func(_ int, s *goquery.Selection) {
if src, exists := s.Attr("src"); exists {
if linkRe.MatchString(src) && !tools.InArray(src, links) {
links = append(links, src)
}
}
})
// background="<>" links
doc.Find("[background]").Each(func(_ int, s *goquery.Selection) {
if bg, exists := s.Attr("background"); exists {
if linkRe.MatchString(bg) && !tools.InArray(bg, links) {
links = append(links, bg)
}
}
})
// url(<>) links in style blocks
matches := urlRe.FindAllStringSubmatch(msg.HTML, -1)
for _, match := range matches {
if len(match) >= 3 {
link := match[2]
if linkRe.MatchString(link) && !tools.InArray(link, links) {
links = append(links, link)
}
}
}
r := MessageAssets{}
r.ID = id
r.Created = time.Now()
r.Assets = links
assets[id] = r
return links, nil
}
// AbsoluteURL will return a full URL regardless whether it is relative or absolute.
// This is used to replace relative CSS url(...) links when proxying.
func absoluteURL(link, baseURL string) (string, error) {
// scheme relative links, eg <script src="//example.com/script.js">
if len(link) > 1 && link[0:2] == "//" {
@@ -156,3 +344,60 @@ func httpError(w http.ResponseWriter, msg string) {
w.Header().Set("Content-Type", "text/plain")
_, _ = fmt.Fprint(w, msg)
}
// SupportedProxyContentType checks if the content-type is supported for proxying.
// This is limited to fonts, images and css only.
func supportedProxyContentType(ct string) bool {
ct = strings.ToLower(ct)
types := []string{
"font/otf",
"font/ttf",
"font/woff",
"font/woff2",
"image/apng",
"image/avif",
"image/bmp",
"image/gif",
"image/jpeg",
"image/jpg",
"image/png",
"image/tiff",
"image/svg+xml",
"image/webp",
"text/css",
}
for _, t := range types {
if strings.HasPrefix(ct, t) {
return true
}
}
return false
}
// SafeDialContext is a custom dialer that checks if the resolved IP addresses are internal before allowing the connection.
func safeDialContext(dialer *net.Dialer) func(ctx context.Context, network, address string) (net.Conn, error) {
return func(ctx context.Context, network, address string) (net.Conn, error) {
host, port, err := net.SplitHostPort(address)
if err != nil {
return nil, err
}
ips, err := net.DefaultResolver.LookupIPAddr(ctx, host)
if err != nil {
return nil, err
}
if !config.AllowInternalHTTPRequests {
for _, ip := range ips {
if tools.IsInternalIP(ip.IP) {
return nil, fmt.Errorf("blocked request to %s (%s): private/reserved address", host, ip)
}
}
}
return dialer.DialContext(ctx, network, net.JoinHostPort(ips[0].IP.String(), port))
}
}

View File

@@ -20,6 +20,7 @@ import (
"github.com/axllent/mailpit/internal/logger"
"github.com/axllent/mailpit/internal/pop3"
"github.com/axllent/mailpit/internal/prometheus"
"github.com/axllent/mailpit/internal/snakeoil"
"github.com/axllent/mailpit/internal/stats"
"github.com/axllent/mailpit/internal/storage"
"github.com/axllent/mailpit/internal/tools"
@@ -31,21 +32,23 @@ import (
)
var (
// AccessControlAllowOrigin CORS policy
AccessControlAllowOrigin string
// htmlPreviewRouteRe is a regexp to match the HTML preview route
htmlPreviewRouteRe *regexp.Regexp
)
// Listen will start the httpd
func Listen() {
setCORSOrigins()
isReady := &atomic.Value{}
isReady.Store(false)
stats.Track()
websockets.MessageHub = websockets.NewHub()
// set allowed websocket origins from configuration
// websockets.SetAllowedOrigins(AccessControlAllowWSOrigins)
go websockets.MessageHub.Run()
go pop3.Run()
@@ -85,9 +88,6 @@ func Listen() {
r.Path(config.Webroot + "search").Handler(middleWareFunc(index)).Methods("GET")
r.Path(config.Webroot).Handler(middleWareFunc(index)).Methods("GET")
// put it all together
http.Handle("/", r)
if auth.UICredentials != nil {
logger.Log().Info("[http] enabling basic authentication")
}
@@ -99,6 +99,13 @@ func Listen() {
Addr: config.HTTPListen,
ReadTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
Handler: r,
}
// add temporary self-signed certificates to get deleted afterwards
for _, keyPair := range snakeoil.Certificates() {
storage.AddTempFile(keyPair.Public)
storage.AddTempFile(keyPair.Private)
}
if config.UITLSCert != "" && config.UITLSKey != "" {
@@ -203,7 +210,7 @@ func apiRoutes() *mux.Router {
func basicAuthResponse(w http.ResponseWriter) {
w.Header().Set("WWW-Authenticate", `Basic realm="Login"`)
w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write([]byte("Unauthorised.\n"))
_, _ = w.Write([]byte("Unauthorized.\n"))
}
// sendAPIAuthMiddleware handles authentication specifically for the send API endpoint
@@ -282,9 +289,12 @@ func middleWareFunc(fn http.HandlerFunc) http.HandlerFunc {
htmlPreviewRouteRe = regexp.MustCompile(`^` + regexp.QuoteMeta(config.Webroot) + `view/[a-zA-Z0-9]+\.html$`)
}
if AccessControlAllowOrigin != "" &&
(strings.HasPrefix(r.RequestURI, config.Webroot+"api/") || htmlPreviewRouteRe.MatchString(r.RequestURI)) {
w.Header().Set("Access-Control-Allow-Origin", AccessControlAllowOrigin)
if strings.HasPrefix(r.RequestURI, config.Webroot+"api/") || htmlPreviewRouteRe.MatchString(r.RequestURI) {
if allowed := corsOriginAccessControl(r); !allowed {
http.Error(w, "Blocked to to CORS violation", http.StatusForbidden)
return
}
w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin"))
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "*")
}
@@ -326,6 +336,12 @@ func addSlashToWebroot(w http.ResponseWriter, r *http.Request) {
// Websocket to broadcast changes
func apiWebsocket(w http.ResponseWriter, r *http.Request) {
if allowed := corsOriginAccessControl(r); !allowed {
http.Error(w, "Blocked to to CORS violation", http.StatusForbidden)
return
}
w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin"))
w.Header().Set("Access-Control-Allow-Headers", "*")
websockets.ServeWs(websockets.MessageHub, w, r)
storage.BroadcastMailboxStats()
}

View File

@@ -130,14 +130,14 @@ func TestAPIv1ToggleReadStatus(t *testing.T) {
// read first 10 IDs
t.Log("Get first 10 IDs")
putIDS := []string{}
putIDs := []string{}
for idx, msg := range m.Messages {
if idx == 10 {
break
}
// store for later
putIDS = append(putIDS, msg.ID)
putIDs = append(putIDs, msg.ID)
}
assertStatsEqual(t, ts.URL+"/api/v1/messages", 100, 100)
@@ -145,7 +145,7 @@ func TestAPIv1ToggleReadStatus(t *testing.T) {
t.Log("Mark first 10 as read")
putData := putDataStruct
putData.Read = true
putData.IDs = putIDS
putData.IDs = putIDs
j, err := json.Marshal(putData)
if err != nil {
t.Error(err.Error())

View File

@@ -17,7 +17,7 @@ export default {
mixins: [CommonMixins],
watch: {
$route(to, from) {
$route() {
// hide mobile menu on URL change
this.hideNav();
},

View File

@@ -21,3 +21,4 @@ $enable-negative-margins: true;
$body-color-dark: #e7eaed;
$offcanvas-border-width: 0;
$body-color: #080808;
$btn-disabled-opacity: 0.4;

View File

@@ -314,6 +314,11 @@ body.blur {
display: none;
}
// dropdown doesn't always appear in correct position inside modals
.dropdown.form-select {
position: relative !important;
}
.message {
&.read {
> div {

View File

@@ -53,5 +53,10 @@ export default {
navigator.setAppBadge(this.mailboxUnread);
},
},
render() {
// to remove webkit warnings about missing template or render function
return false;
},
};
</script>

View File

@@ -112,5 +112,10 @@ export default {
this.favicon.href = canvas.toDataURL("image/png");
},
},
render() {
// to remove webkit warnings about missing template or render function
return false;
},
};
</script>

View File

@@ -52,7 +52,7 @@ export default {
let response;
try {
response = JSON.parse(e.data);
} catch (e) {
} catch {
return;
}
@@ -128,7 +128,7 @@ export default {
}
};
ws.onclose = (e) => {
ws.onclose = () => {
if (this.socketLastConnection === 0) {
// connection failed immediately after connecting to Mailpit implies proxy websockets aren't configured
console.log("Unable to connect to websocket, disabling websocket support");

View File

@@ -14,6 +14,9 @@ export default {
timezones,
chaosConfig: false,
chaosUpdated: false,
defaultReleaseAddressesOptions: localStorage.getItem("defaultReleaseAddresses")
? JSON.parse(localStorage.getItem("defaultReleaseAddresses"))
: [], // set with default release addresses
};
},
@@ -45,11 +48,13 @@ export default {
mounted() {
this.setTheme();
this.$nextTick(() => {
Tags.init("select.tz");
});
mailbox.skipConfirmations = !!localStorage.getItem("skip-confirmations");
mailbox.skipConfirmations = localStorage.getItem("skip-confirmations");
window.setTimeout(() => {
Tags.init("select.tz");
Tags.init("select.default-release-addresses");
}, 500);
},
methods: {
@@ -98,7 +103,7 @@ export default {
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<ul v-if="mailbox.uiConfig.ChaosEnabled" id="myTab" class="nav nav-tabs" role="tablist">
<ul id="myTab" class="nav nav-tabs" role="tablist">
<li class="nav-item" role="presentation">
<button
id="ui-tab"
@@ -113,7 +118,25 @@ export default {
Web UI
</button>
</li>
<li class="nav-item" role="presentation">
<li
v-if="mailbox.uiConfig.MessageRelay && mailbox.uiConfig.MessageRelay.Enabled"
class="nav-item"
role="presentation"
>
<button
id="relay-tab"
class="nav-link"
data-bs-toggle="tab"
data-bs-target="#relay-tab-pane"
type="button"
role="tab"
aria-controls="relay-tab-pane"
aria-selected="false"
>
Message release
</button>
</li>
<li v-if="mailbox.uiConfig.ChaosEnabled" class="nav-item" role="presentation">
<button
id="chaos-tab"
class="nav-link"
@@ -234,6 +257,50 @@ export default {
</div>
</div>
<!-- Default relay addresses -->
<div
v-if="mailbox.uiConfig.MessageRelay && mailbox.uiConfig.MessageRelay.Enabled"
id="relay-tab-pane"
class="tab-pane fade"
role="tabpanel"
aria-labelledby="relay-tab"
tabindex="0"
>
<div class="my-3 mb-5">
<label class="form-label">Default release address(es)</label>
<div class="form-text mb-2">
You can designate the default "send to" addresses here, which will automatically
populate the field in the message release dialog. This setting applies only to your
browser. If this field is left empty, it will revert to the original recipients of
the message.
</div>
<select
v-model="mailbox.defaultReleaseAddresses"
class="form-select tag-selector default-release-addresses"
multiple
data-allow-new="true"
data-clear-end="true"
data-allow-clear="true"
data-placeholder="Enter email addresses..."
data-add-on-blur="true"
data-badge-style="primary"
data-regex='^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'
data-separator="|,|"
>
<option value="">Enter email addresses...</option>
<!-- you need at least one option with the placeholder -->
<option
v-for="t in defaultReleaseAddressesOptions"
:key="'address+' + t"
:value="t"
>
{{ t }}
</option>
</select>
<div class="invalid-feedback">Invalid email address</div>
</div>
</div>
<div
v-if="mailbox.uiConfig.ChaosEnabled"
id="chaos-tab-pane"

View File

@@ -9,7 +9,7 @@ export default {
return {
mailbox,
editableTags: [],
validTagRe: /^([a-zA-Z0-9\- ._]){1,}$/,
validTagRe: /^([a-zA-Z0-9\- ._@]){1,100}$/,
tagToDelete: false,
};
},
@@ -28,7 +28,7 @@ export default {
methods: {
validTag(t) {
if (!t.after.match(/^([a-zA-Z0-9\- _.]){1,}$/)) {
if (!t.after.match(/^([a-zA-Z0-9\- ._@]){1,100}$/)) {
return false;
}

View File

@@ -47,14 +47,14 @@ export default {
},
markAllRead() {
this.put(this.resolve(`/api/v1/messages`), { read: true }, (response) => {
this.put(this.resolve(`/api/v1/messages`), { read: true }, () => {
window.scrollInPlace = true;
this.loadMessages();
});
},
deleteAllMessages() {
this.delete(this.resolve(`/api/v1/messages`), false, (response) => {
this.delete(this.resolve(`/api/v1/messages`), false, () => {
pagination.start = 0;
this.loadMessages();
});
@@ -89,7 +89,7 @@ export default {
<button
v-if="mailbox.skipConfirmations"
class="list-group-item list-group-item-action"
:disabled="!mailbox.messages_unread"
:disabled="!mailbox.unread"
@click="markAllRead"
>
<i class="bi bi-eye-fill me-1"></i>
@@ -100,7 +100,7 @@ export default {
class="list-group-item list-group-item-action"
data-bs-toggle="modal"
data-bs-target="#MarkAllReadModal"
:disabled="!mailbox.messages_unread"
:disabled="!mailbox.unread"
>
<i class="bi bi-eye-fill me-1"></i>
Mark all read

View File

@@ -85,8 +85,9 @@ export default {
<template>
<select
v-model="pagination.limit"
class="form-select form-select-sm d-inline w-auto me-2"
class="form-select form-select-sm d-inline w-auto me-2 me-xl-3"
:disabled="total == 0"
title="The number of messages displayed per page"
@change="changeLimit"
>
<option v-for="option in limitOptions" :key="option" :value="option">{{ option }}</option>
@@ -98,11 +99,11 @@ export default {
<small>of</small>
{{ formatNumber(total) }}
</template>
<span v-else class="text-muted">0 of 0</span>
<span v-else class="text-light">0 of 0</span>
</small>
<button
class="btn btn-outline-light ms-2 me-1"
class="btn btn-outline-light ms-2 ms-xl-3 me-1"
:disabled="!canPrev"
:title="'View previous ' + pagination.limit + ' messages'"
@click="viewPrev"

View File

@@ -28,7 +28,7 @@ export default {
if (!mailbox.selected.length) {
return false;
}
this.put(this.resolve(`/api/v1/messages`), { Read: true, IDs: mailbox.selected }, (response) => {
this.put(this.resolve(`/api/v1/messages`), { Read: true, IDs: mailbox.selected }, () => {
window.scrollInPlace = true;
this.loadMessages();
});
@@ -43,7 +43,7 @@ export default {
if (!mailbox.selected.length) {
return false;
}
this.put(this.resolve(`/api/v1/messages`), { Read: false, IDs: mailbox.selected }, (response) => {
this.put(this.resolve(`/api/v1/messages`), { Read: false, IDs: mailbox.selected }, () => {
window.scrollInPlace = true;
this.loadMessages();
});
@@ -51,13 +51,12 @@ export default {
// universal handler to delete current or selected messages
deleteMessages() {
let ids = [];
ids = JSON.parse(JSON.stringify(mailbox.selected));
const ids = JSON.parse(JSON.stringify(mailbox.selected));
if (!ids.length) {
return false;
}
this.delete(this.resolve(`/api/v1/messages`), { IDs: ids }, (response) => {
this.delete(this.resolve(`/api/v1/messages`), { IDs: ids }, () => {
window.scrollInPlace = true;
this.loadMessages();
});

View File

@@ -257,7 +257,10 @@ export default {
if (platforms) {
try {
this.platforms = JSON.parse(platforms);
} catch (e) {}
} catch {
// if parsing fails, reset to default
this.platforms = [];
}
}
// set all options

View File

@@ -153,7 +153,7 @@ export default {
this.error = error.message;
}
})
.then((result) => {
.then(() => {
// always run
this.loading = false;
});

View File

@@ -1,5 +1,6 @@
<script>
import commonMixins from "../../mixins/CommonMixins";
import { mailbox } from "../../stores/mailbox";
import ICAL from "ical.js";
import dayjs from "dayjs";
@@ -19,6 +20,7 @@ export default {
data() {
return {
mailbox,
ical: false,
};
},
@@ -74,46 +76,125 @@ export default {
</script>
<template>
<div class="mt-4 border-top pt-4">
<a
<hr />
<button
class="btn btn-sm btn-outline-secondary mb-3"
@click="mailbox.showAttachmentDetails = !mailbox.showAttachmentDetails"
>
<i class="bi me-1" :class="mailbox.showAttachmentDetails ? 'bi-eye-slash' : 'bi-eye'"></i>
{{ mailbox.showAttachmentDetails ? "Hide" : "Show" }} attachment details
</button>
<div class="row gx-1 w-100">
<div
v-for="part in attachments"
:key="part.PartID"
:href="resolve('/api/v1/message/' + message.ID + '/part/' + part.PartID)"
class="card attachment float-start me-3 mb-3"
target="_blank"
style="width: 180px"
@click="openAttachment(part, $event)"
:class="mailbox.showAttachmentDetails ? 'col-12' : 'col-auto'"
>
<img
v-if="isImage(part)"
:src="resolve('/api/v1/message/' + message.ID + '/part/' + part.PartID + '/thumb')"
class="card-img-top"
alt=""
/>
<img
v-else
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAB4AQMAAABhKUq+AAAAA1BMVEX///+nxBvIAAAAGUlEQVQYGe3BgQAAAADDoPtTT+EA1QAAgFsLQAAB12s2WgAAAABJRU5ErkJggg=="
class="card-img-top"
alt=""
/>
<div v-if="!isImage(part)" class="icon">
<i class="bi" :class="attachmentIcon(part)"></i>
<div class="row gx-1 mb-3">
<div class="col-auto">
<a
:href="resolve('/api/v1/message/' + message.ID + '/part/' + part.PartID)"
class="card attachment float-start me-3 mb-3"
target="_blank"
style="width: 180px"
@click="openAttachment(part, $event)"
>
<img
v-if="isImage(part)"
:src="resolve('/api/v1/message/' + message.ID + '/part/' + part.PartID + '/thumb')"
class="card-img-top"
alt=""
/>
<img
v-else
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAB4AQMAAABhKUq+AAAAA1BMVEX///+nxBvIAAAAGUlEQVQYGe3BgQAAAADDoPtTT+EA1QAAgFsLQAAB12s2WgAAAABJRU5ErkJggg=="
class="card-img-top"
alt=""
/>
<div v-if="!isImage(part)" class="icon">
<i class="bi" :class="attachmentIcon(part)"></i>
</div>
<div class="card-body border-0">
<p class="mb-1">
<i class="bi me-1" :class="attachmentIcon(part)"></i>
<small>{{ getFileSize(part.Size) }}</small>
</p>
<p class="card-text mb-0 small">
{{ part.FileName != "" ? part.FileName : "[ unknown ]" + part.ContentType }}
</p>
</div>
<div class="card-footer small border-0 text-center text-truncate">
{{ part.FileName != "" ? part.FileName : "[ unknown ]" + part.ContentType }}
</div>
</a>
</div>
<div v-if="mailbox.showAttachmentDetails" class="col">
<h5 class="mb-1">
<a
:href="resolve('/api/v1/message/' + message.ID + '/part/' + part.PartID)"
class="me-2"
@click="openAttachment(part, $event)"
>
{{ part.FileName != "" ? part.FileName : "[ unknown ]" + part.ContentType }}
</a>
<small class="text-muted fw-light">
<small>({{ getFileSize(part.Size) }})</small>
</small>
</h5>
<p class="mb-1 small"><strong>Disposition</strong>: {{ part.ContentDisposition }}</p>
<p class="mb-2 small">
<strong>Content type</strong>: <code>{{ part.ContentType }}</code>
</p>
<p class="m-0 small">
<strong>MD5</strong>:
<button
v-if="copyToClipboardSupported"
class="btn btn-sm btn-link p-0"
title="Click to copy to clipboard"
@click="copyToClipboard(part.Checksums.MD5, $event)"
>
{{ part.Checksums.MD5 }}
<i v-if="!copiedText[part.Checksums.MD5]" class="bi bi-clipboard ms-1"></i>
<i v-else class="bi bi-check2-square ms-1 text-success"></i>
</button>
<code v-else>{{ part.Checksums.MD5 }}</code>
</p>
<p class="m-0 small">
<strong>SHA1</strong>:
<button
v-if="copyToClipboardSupported"
class="btn btn-link p-0"
title="Click to copy to clipboard"
@click="copyToClipboard(part.Checksums.SHA1, $event)"
>
{{ part.Checksums.SHA1 }}
<i v-if="!copiedText[part.Checksums.SHA1]" class="bi bi-clipboard ms-1"></i>
<i v-else class="bi bi-check2-square ms-1 text-success"></i>
</button>
<code v-else>{{ part.Checksums.SHA1 }}</code>
</p>
<p class="m-0 small">
<strong>SHA256</strong>:
<button
v-if="copyToClipboardSupported"
class="btn btn-sm btn-link p-0"
title="Click to copy to clipboard"
@click="copyToClipboard(part.Checksums.SHA256, $event)"
>
{{ part.Checksums.SHA256 }}
<i v-if="!copiedText[part.Checksums.SHA256]" class="bi bi-clipboard ms-1"></i>
<i v-else class="bi bi-check2-square ms-1 text-success"></i>
</button>
<code v-else>{{ part.Checksums.SHA256 }}</code>
</p>
</div>
</div>
<div class="card-body border-0">
<p class="mb-1">
<i class="bi me-1" :class="attachmentIcon(part)"></i>
<small>{{ getFileSize(part.Size) }}</small>
</p>
<p class="card-text mb-0 small">
{{ part.FileName != "" ? part.FileName : "[ unknown ]" + part.ContentType }}
</p>
</div>
<div class="card-footer small border-0 text-center text-truncate">
{{ part.FileName != "" ? part.FileName : "[ unknown ]" + part.ContentType }}
</div>
</a>
</div>
</div>
<!-- ICS Modal -->
<div id="ICSView" class="modal fade" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-lg">
<div class="modal-content">

View File

@@ -107,11 +107,12 @@ export default {
"vspace",
"xml:lang",
],
FORBID_ATTR: ["script"],
FORBID_ATTR: ["script"], // all JavaScript should be removed
ALLOW_UNKNOWN_PROTOCOLS: true, // allow link href protocols like myapp:// etc
});
// for debugging
// this.debugDOMPurify(DOMPurify.removed)
// this.debugDOMPurify(DOMPurify.removed);
return clean;
},
@@ -142,12 +143,12 @@ export default {
window.addEventListener("resize", this.resizeIFrames);
const headersTab = document.getElementById("nav-headers-tab");
headersTab.addEventListener("shown.bs.tab", (event) => {
headersTab.addEventListener("shown.bs.tab", () => {
this.loadHeaders = true;
});
const rawTab = document.getElementById("nav-raw-tab");
rawTab.addEventListener("shown.bs.tab", (event) => {
rawTab.addEventListener("shown.bs.tab", () => {
this.srcURI = this.resolve("/api/v1/message/" + this.message.ID + "/raw");
this.resizeIFrames();
});
@@ -179,7 +180,7 @@ export default {
this.isHTMLTabSelected();
document.querySelectorAll('button[data-bs-toggle="tab"]').forEach((listObj) => {
listObj.addEventListener("shown.bs.tab", (event) => {
listObj.addEventListener("shown.bs.tab", () => {
this.isHTMLTabSelected();
});
});
@@ -202,7 +203,9 @@ export default {
anchorEl.setAttribute("target", "_blank");
}
}
} catch (error) {}
} catch {
// ignore errors when accessing the iframe content
}
this.resizeIFrames();
}
}, 500);
@@ -279,7 +282,7 @@ export default {
Tags: this.messageTags,
};
this.put(this.resolve("/api/v1/tags"), data, (response) => {
this.put(this.resolve("/api/v1/tags"), data, () => {
window.scrollInPlace = true;
this.$emit("loadMessages");
});
@@ -289,15 +292,24 @@ export default {
textToHTML(s) {
let html = s;
// full links with http(s)
const re = /(\b(https?|ftp):\/\/[-\w@:%_+'!.~#?,&//=;]+)/gim;
html = html.replace(re, "˱˱˱a href=ˠˠˠ$&ˠˠˠ target=_blank rel=noopener˲˲˲$&˱˱˱/a˲˲˲");
// RFC2396 appendix E states angle brackets are recommended for text/plain emails to
// recognize potential spaces in between the URL
// @see https://www.rfc-editor.org/rfc/rfc2396#appendix-E
const angleLinks = /<((https?|ftp):\/\/[-\w@:%_+'!.~#?,&//=; ][^>]+)>/gim;
html = html.replace(angleLinks, "<˱˱˱a href=ˠˠˠ$1ˠˠˠ target=_blank rel=noopener˲˲˲$1˱˱˱/a˲˲˲>");
// find links without angle brackets, starting with http(s) or ftp
const regularLinks = /([^ˠ˲]\b)(((https?|ftp):\/\/[-\w@:%_+'!.~#?,&//=;]+))/gim;
html = html.replace(regularLinks, "$1˱˱˱a href=ˠˠˠ$2ˠˠˠ target=_blank rel=noopener˲˲˲$2˱˱˱/a˲˲˲");
// plain www links without https?:// prefix
const re2 = /(^|[^/])(www\.[\S]+(\b|$))/gim;
html = html.replace(re2, "$1˱˱˱a href=ˠˠˠhttp://$2ˠˠˠ target=ˠˠˠ_blankˠˠˠ rel=ˠˠˠnoopenerˠˠˠ˲˲˲$2˱˱˱/a˲˲˲");
const shortLinks = /(^|[^/])(www\.[\S]+(\b|$))/gim;
html = html.replace(
shortLinks,
"$1˱˱˱a href=ˠˠˠhttp://$2ˠˠˠ target=ˠˠˠ_blankˠˠˠ rel=ˠˠˠnoopenerˠˠˠ˲˲˲$2˱˱˱/a˲˲˲",
);
// escape to HTML & convert <>" back
// escape to HTML & convert <>" characters back
html = html
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
@@ -455,7 +467,7 @@ export default {
data-allow-clear="true"
data-placeholder="Add tags..."
data-badge-style="secondary"
data-regex="^([a-zA-Z0-9\-\ \_\.]){1,}$"
data-regex="^([a-zA-Z0-9\-\ \_\.@]){1,100}$"
data-separator="|,|"
>
<option value="">Type a tag...</option>

View File

@@ -44,7 +44,20 @@ export default {
// include only unique email addresses, regardless of casing
this.allAddresses = JSON.parse(JSON.stringify([...new Map(a.map((ad) => [ad.toLowerCase(), ad])).values()]));
this.addresses = this.allAddresses;
// include default release addresses from mailbox settings
const defaultAddr = mailbox.defaultReleaseAddresses;
for (const i in defaultAddr) {
if (!this.allAddresses.includes(defaultAddr[i])) {
this.allAddresses.push(defaultAddr[i]);
}
}
if (defaultAddr.length === 0) {
// prefill with all addresses if no default is set
this.addresses = this.allAddresses;
} else {
this.addresses = defaultAddr;
}
},
methods: {
@@ -64,7 +77,7 @@ export default {
To: this.addresses,
};
this.post(this.resolve("/api/v1/message/" + this.message.ID + "/release"), data, (response) => {
this.post(this.resolve("/api/v1/message/" + this.message.ID + "/release"), data, () => {
this.modal("ReleaseModal").hide();
if (this.deleteAfterRelease) {
this.$emit("delete");
@@ -140,6 +153,13 @@ export default {
<option v-for="t in allAddresses" :key="'address+' + t" :value="t">{{ t }}</option>
</select>
<div class="invalid-feedback">Invalid email address</div>
<div class="form-text mt-1">
Default release addresses can be configured in
<a href="#" data-bs-toggle="modal" data-bs-target="#SettingsModal">
<i class="bi bi-gear-fill ms-1"></i>
Settings </a
>.
</div>
</div>
</div>
<div class="row mb-3">

View File

@@ -27,9 +27,13 @@ export default {
methods: {
initScreenshot() {
this.loading = 1;
const baseUrl = `${location.protocol}//${location.host}/`;
// absolute proxy URL
const proxy = new URL(this.resolve("/proxy"), baseUrl).href;
const urlRegex = /(url\(('|")?(https?:\/\/[^)'"]+)('|")?\))/gim;
// remove base tag, if set
let h = this.message.HTML.replace(/<base .*>/im, "");
const proxy = this.resolve("/proxy");
// Outlook hacks - else screenshot returns blank image
h = h.replace(/<html [^>]+>/gim, "<html>"); // remove html attributes
@@ -37,19 +41,10 @@ export default {
h = h.replace(/<o:/gm, "<"); // replace `<o:p>` tags with `<p>`
h = h.replace(/<\/o:/gm, "</"); // replace `</o:p>` tags with `</p>`
// update any inline `url(...)` absolute links
const urlRegex = /(url\(('|")?(https?:\/\/[^)'"]+)('|")?\))/gim;
h = h.replaceAll(urlRegex, (match, p1, p2, p3) => {
if (typeof p2 === "string") {
return `url(${p2}${proxy}?url=` + encodeURIComponent(this.decodeEntities(p3)) + `${p2})`;
}
return `url(${proxy}?url=` + encodeURIComponent(this.decodeEntities(p3)) + `)`;
});
// create temporary document to manipulate
const doc = document.implementation.createHTMLDocument();
doc.open();
doc.write(h);
doc.writeln(h);
doc.close();
// remove any <script> tags
@@ -58,17 +53,30 @@ export default {
i.parentNode.removeChild(i);
}
// replace any url(...) links in <style> blocks
const styles = doc.getElementsByTagName("style");
for (const i of styles) {
i.innerHTML = i.innerHTML.replaceAll(urlRegex, (match, p1, p2, p3) => {
if (typeof p2 === "string") {
// quoted URL
return (
`url(${p2}${proxy}?data=` + btoa(this.message.ID + ":" + this.decodeEntities(p3)) + `${p2})`
);
}
return `url(${proxy}?data=` + btoa(this.message.ID + ":" + this.decodeEntities(p3)) + `)`;
});
}
// replace stylesheet links with proxy links
const stylesheets = doc.getElementsByTagName("link");
for (const i of stylesheets) {
const src = i.getAttribute("href");
if (
src &&
src.match(/^https?:\/\//i) &&
src.indexOf(window.location.origin + window.location.pathname) !== 0
) {
i.setAttribute("href", `${proxy}?url=` + encodeURIComponent(this.decodeEntities(src)));
i.setAttribute("href", `${proxy}?data=` + btoa(this.message.ID + ":" + this.decodeEntities(src)));
}
}
@@ -81,7 +89,7 @@ export default {
src.match(/^https?:\/\//i) &&
src.indexOf(window.location.origin + window.location.pathname) !== 0
) {
i.setAttribute("src", `${proxy}?url=` + encodeURIComponent(this.decodeEntities(src)));
i.setAttribute("src", `${proxy}?data=` + btoa(this.message.ID + ":" + this.decodeEntities(src)));
}
}
@@ -96,7 +104,10 @@ export default {
src.indexOf(window.location.origin + window.location.pathname) !== 0
) {
// replace with proxy link
i.setAttribute("background", `${proxy}?url=` + encodeURIComponent(this.decodeEntities(src)));
i.setAttribute(
"background",
`${proxy}?data=` + btoa(this.message.ID + ":" + this.decodeEntities(src)),
);
}
}

View File

@@ -20,9 +20,16 @@ export default {
return {
loading: 0,
tagColorCache: {},
copiedText: {}, // used for clipboard copy feedback
};
},
computed: {
copyToClipboardSupported() {
return !!navigator.clipboard;
},
},
methods: {
resolve(u) {
return this.$router.resolve(u).href;
@@ -222,12 +229,15 @@ export default {
allAttachments(message) {
const a = [];
for (const i in message.Attachments) {
message.Attachments[i].ContentDisposition = "Attachment";
a.push(message.Attachments[i]);
}
for (const i in message.OtherParts) {
message.OtherParts[i].ContentDisposition = "Other";
a.push(message.OtherParts[i]);
}
for (const i in message.Inline) {
message.Inline[i].ContentDisposition = "Inline";
a.push(message.Inline[i]);
}
@@ -288,5 +298,21 @@ export default {
return this.tagColorCache[s];
},
// Copy to clipboard functionality
copyToClipboard(text) {
navigator.clipboard.writeText(text).then(
() => {
this.copiedText[text] = true;
setTimeout(() => {
delete this.copiedText[text];
}, 2000);
},
() => {
// failure
alert("Failed to copy to clipboard");
},
);
},
},
};

View File

@@ -14,7 +14,7 @@ export default {
},
watch: {
"mailbox.refresh": function (v) {
"mailbox.refresh"(v) {
if (v) {
// trigger a refresh
this.loadMessages();
@@ -45,9 +45,9 @@ export default {
const params = {};
mailbox.selected = [];
params["limit"] = pagination.limit;
params.limit = pagination.limit;
if (pagination.start > 0) {
params["start"] = pagination.start;
params.start = pagination.start;
}
this.get(this.apiURI, params, (response) => {

View File

@@ -20,6 +20,9 @@ export const mailbox = reactive({
appInfo: {}, // application information
uiConfig: {}, // configuration for UI
lastMessage: false, // return scrolling
defaultReleaseAddresses: localStorage.getItem("defaultReleaseAddresses")
? JSON.parse(localStorage.getItem("defaultReleaseAddresses"))
: [], // default release addresses for released messages
// settings
showTagColors: !localStorage.getItem("hideTagColors"),
@@ -29,11 +32,12 @@ export const mailbox = reactive({
timeZone: localStorage.getItem("timeZone")
? localStorage.getItem("timeZone")
: Intl.DateTimeFormat().resolvedOptions().timeZone,
showAttachmentDetails: localStorage.getItem("showAttachmentDetails"), // show attachment details
});
watch(
() => mailbox.count,
(v) => {
() => {
mailbox.selected = [];
},
);
@@ -82,6 +86,17 @@ watch(
},
);
watch(
() => mailbox.defaultReleaseAddresses,
(v) => {
if (v.length) {
localStorage.setItem("defaultReleaseAddresses", JSON.stringify(v));
} else {
localStorage.removeItem("defaultReleaseAddresses");
}
},
);
watch(
() => mailbox.timeZone,
(v) => {
@@ -92,3 +107,14 @@ watch(
}
},
);
watch(
() => mailbox.showAttachmentDetails,
(v) => {
if (v) {
localStorage.setItem("showAttachmentDetails", "1");
} else {
localStorage.removeItem("showAttachmentDetails");
}
},
);

View File

@@ -36,7 +36,7 @@ export default {
},
watch: {
$route(to, from) {
$route() {
this.loadMailbox();
},
},
@@ -176,7 +176,7 @@ export default {
</script>
<template>
<div class="navbar navbar-expand-lg navbar-dark row flex-shrink-0 bg-primary text-white d-print-none">
<div class="navbar navbar-expand-lg row flex-shrink-0 bg-primary text-white d-print-none" data-bs-theme="dark">
<div class="col-xl-2 col-md-3 col-auto pe-0">
<RouterLink to="/" class="navbar-brand text-white me-0" @click="reloadMailbox">
<img :src="resolve('/mailpit.svg')" alt="Mailpit" />

View File

@@ -28,6 +28,7 @@ export default {
mailbox,
pagination,
message: false,
loadReleaseModal: false,
errorMessage: false,
apiSideNavURI: false,
apiSideNavParams: URLSearchParams,
@@ -94,7 +95,7 @@ export default {
},
watch: {
$route(to, from) {
$route() {
this.loadMessage();
},
},
@@ -442,7 +443,11 @@ export default {
if (pagination.limit !== pagination.defaultLimit) {
p.limit = pagination.limit.toString();
}
this.$router.push("/?" + new URLSearchParams(p).toString());
if (p.start || p.limit) {
this.$router.push("/?" + new URLSearchParams(p).toString());
} else {
this.$router.push("/");
}
}
},
@@ -451,19 +456,25 @@ export default {
},
initReleaseModal() {
this.modal("ReleaseModal").show();
window.setTimeout(() => {
// delay to allow elements to load / focus
this.$refs.ReleaseRef.initTags();
document.querySelector('#ReleaseModal input[role="combobox"]').focus();
}, 500);
// reset releaseMessage to force re-render so default release addresses can be included
this.loadReleaseModal = false;
this.$nextTick(() => {
this.loadReleaseModal = true;
this.$nextTick(() => {
this.modal("ReleaseModal").show();
window.setTimeout(() => {
// delay to allow elements to load / focus
this.$refs.ReleaseRef.initTags();
}, 250);
});
});
},
},
};
</script>
<template>
<div class="navbar navbar-expand-lg navbar-dark row flex-shrink-0 bg-primary text-white d-print-none">
<div class="navbar navbar-expand-lg row flex-shrink-0 bg-primary text-white d-print-none" data-bs-theme="dark">
<div class="d-none d-xl-block col-xl-3 col-auto pe-0">
<RouterLink to="/" class="navbar-brand text-white me-0" @click="pagination.start = 0">
<img :src="resolve('/mailpit.svg')" alt="Mailpit" />
@@ -485,11 +496,11 @@ export default {
title="Release message"
@click="initReleaseModal()"
>
<i class="bi bi-send"></i>
<i class="bi bi-send me-md-2"></i>
<span class="d-none d-md-inline">Release</span>
</button>
<button class="btn btn-outline-light me-1 me-sm-2" title="Delete message" @click="deleteMessage()">
<i class="bi bi-trash-fill"></i>
<i class="bi bi-trash-fill me-md-2"></i>
<span class="d-none d-md-inline">Delete</span>
</button>
</div>
@@ -707,7 +718,7 @@ export default {
<AboutMailpit modals />
<AjaxLoader :loading="loading" />
<Release
v-if="mailbox.uiConfig.MessageRelay && message"
v-if="mailbox.uiConfig.MessageRelay && loadReleaseModal"
ref="ReleaseRef"
:message="message"
@delete="deleteMessage"

View File

@@ -36,7 +36,7 @@ export default {
},
watch: {
$route(to, from) {
$route() {
this.doSearch();
},
},
@@ -124,7 +124,7 @@ export default {
</script>
<template>
<div class="navbar navbar-expand-lg navbar-dark row flex-shrink-0 bg-primary text-white d-print-none">
<div class="navbar navbar-expand-lg row flex-shrink-0 bg-primary text-white d-print-none" data-bs-theme="dark">
<div class="col-xl-2 col-md-3 col-auto pe-0">
<RouterLink to="/" class="navbar-brand text-white me-0" @click="pagination.start = 0">
<img :src="resolve('/mailpit.svg')" alt="Mailpit" />

View File

@@ -1345,9 +1345,27 @@
"x-go-package": "github.com/axllent/mailpit/internal/stats"
},
"Attachment": {
"description": "Attachment struct for inline and attachments",
"description": "Attachment struct for inline images and attachments",
"type": "object",
"properties": {
"Checksums": {
"description": "File checksums",
"type": "object",
"properties": {
"MD5": {
"description": "MD5 checksum hash of file",
"type": "string"
},
"SHA1": {
"description": "SHA1 checksum hash of file",
"type": "string"
},
"SHA256": {
"description": "SHA256 checksum hash of file",
"type": "string"
}
}
},
"ContentID": {
"description": "Content ID",
"type": "string"

View File

@@ -16,6 +16,10 @@ var (
// RateLimit is the minimum number of seconds between requests
RateLimit = 1
// Delay is the number of seconds to wait before sending each webhook request
// This can allow for other processing to complete before the webhook is triggered.
Delay = 0
rl rate.Sometimes
rateLimiterSet bool
@@ -38,6 +42,11 @@ func Send(msg any) {
}
go func() {
// Apply delay if configured
if Delay > 0 {
time.Sleep(time.Duration(Delay) * time.Second)
}
rl.Do(func() {
b, err := json.Marshal(msg)
if err != nil {

View File

@@ -34,8 +34,11 @@ var (
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool { return true }, // allow multi-domain
EnableCompression: true, // experimental compression
EnableCompression: true,
CheckOrigin: func(_ *http.Request) bool {
// origin is checked via server.go's CORS settings
return true
},
}
// Client is a middleman between the websocket connection and the hub.
@@ -144,5 +147,5 @@ func ServeWs(hub *Hub, w http.ResponseWriter, r *http.Request) {
func basicAuthResponse(w http.ResponseWriter) {
w.Header().Set("WWW-Authenticate", `Basic realm="Login"`)
w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write([]byte("Unauthorised.\n"))
_, _ = w.Write([]byte("Unauthorized.\n"))
}