VOL. I · NO. 1
MAY 31, 2026
✦ TECHNOLOGY SPECIAL

The Internet Times

All the protocols that are fit to fix.

Technical Reference

Spec

Complete API reference for @smart-mailto/core. Types, functions, configuration, and architecture.

Parser

RFC 6068-compliant mailto: URI parsing and building. All string values are decoded (not URL-encoded) in the output.

parseMailto(href)

Parses a mailto: URI string into a structured MailtoParams object.

const params = parseMailto(
  'mailto:hello@example.com?cc=boss@site.com&subject=Hi&body=Hello'
);
// → {
//   to: ['hello@example.com'],
//   cc: ['boss@site.com'],
//   subject: 'Hi',
//   body: 'Hello'
// }

buildMailtoHref(params)

Serializes a MailtoParams object back into a mailto: URI string.

buildMailtoHref({
  to: ['hello@example.com'],
  subject: 'Hello',
  body: 'World'
});
// → 'mailto:hello@example.com?subject=Hello&body=World'

isValidMailtoParams(params)

Returns true if the params object has at least one recipient.

Resolver

Resolves which providers to show for a given mailto: context. Resolution order: custom → persisted preference → email domain detection → preferredProvider override → geo-ordered list.

const params = parseMailto('mailto:hello@gmail.com');
const resolved = resolveProviders(params, { autoDetectGeo: true });

// resolved: ResolvedProviders
// {
//   providers: Provider[],   // ordered list to display
//   detectedRegion: string,  // e.g. 'ru' | 'global'
//   signals: GeoSignals,     // raw browser signals
//   detectedFromEmail: string | null  // provider ID if domain matched
// }

Live: resolveProviders

Paste any email to see geo detection and provider resolution

Region: Global

Signals: UTC · en-US

Providers: gmail, outlook-personal, yahoo, icloud

Domain match: gmail

Geo Detection

Zero-network geo detection using only browser APIs. Maps IANA timezone + navigator.language to regional provider priorities. Runs in <1ms, no external requests.

collectGeoSignals()

Timezone: UTC

Locale: en-US

Languages: en-US

Mobile: no

iOS: no

Android: no

detectRegionLabel(signals)

Returns a human-readable region string:

Europe/Moscow Russia/CIS

Asia/Tokyo Japan

America/New_York Global

Email Domain Detector

Maps email domains to provider IDs. Used during resolution to highlight the user's existing email provider.

detectProviderFromEmail('hello@gmail.com');
// → 'gmail'

detectProviderFromEmail('user@outlook.com');
// → 'outlook-personal'

detectProviderFromEmail('user@protonmail.com');
// → 'protonmail'

getDomainsForProvider('gmail');
// → ['gmail.com', 'googlemail.com']

Storage

localStorage-based preference persistence. All operations are SSR-safe and silently fail in incognito/private browsing.

savePreference('gmail');         // Persist user's choice
loadPreference();                // → 'gmail' | null
clearPreference();               // Remove persisted choice
isStorageAvailable();            // → boolean (false in SSR/incognito)

Initialization

Global initialization via capture-phase event delegation on document. Intercepts all mailto: link clicks. Modal and icons are dynamically imported to keep the core bundle tiny.

import { initSmartMailto, destroySmartMailto, isInitialized, updateConfig } from '@smart-mailto/core';

const destroy = initSmartMailto({
  theme: 'dark',
  autoDetectGeo: true,
  maxProviders: 6,
  // ...config
});

destroy();          // Remove listeners, clean up
isInitialized();    // → boolean
updateConfig({ theme: 'light' });  // Update config at runtime

Architecture notes

  • Uses capture-phase (capture: true) on document to intercept all mailto: links including dynamically added ones
  • Modal (modal.ts) and icons (icons.ts) are dynamically imported on first trigger
  • Safari popup blocker: window.open() is called synchronously within the user click handler
  • Shadow DOM is used for modal CSS isolation — host page styles cannot leak in

SmartMailtoConfig

Full configuration interface. All options are optional and have sensible defaults.

NameTypeDescription
theme(opt)'dark' | 'light' | 'auto'Visual theme for the modal. Defaults to auto (prefers-color-scheme).Default: 'auto'
autoDetectGeo(opt)booleanUse browser heuristics to order providers by region. Defaults to true.Default: true
preferredProvider(opt)stringForce a specific provider ID to the top of the list.
maxProviders(opt)numberMaximum number of provider buttons to show.Default: 6
includeNative(opt)booleanInclude "Open in Native Mail App" option.Default: true on mobile
includeCopy(opt)booleanAlways include a "Copy Email Address" button.Default: true
excludeProviders(opt)string[]Hide specific provider IDs from the list.
customProviders(opt)Provider[]Inject custom/enterprise providers. Prepended to the list.
classNames(opt)ClassNamesCSS class overrides for headless/unstyled mode.
i18n(opt)Partial<I18nStrings>Override UI strings for internationalization.
rememberChoice(opt)booleanPersist user's provider choice to localStorage.Default: true
storageKey(opt)stringlocalStorage key for persisted provider choice.Default: 'smart-mailto:preferred'
onOpen(opt)(provider, params) => voidLifecycle hook: fired when user clicks a provider.
onCopy(opt)(email) => voidLifecycle hook: fired when user copies an email address.
onClose(opt)() => voidLifecycle hook: fired when modal is dismissed.
onShow(opt)(params, providers) => voidLifecycle hook: fired when modal is first shown.

Provider Registry

32+ email providers with verified compose URLs. Registry is in packages/core/src/providers.ts.

PROVIDERS           // ReadonlyRecord<string, Provider>
getProvider(id)     // → Provider | undefined
getAllProviders()   // → Provider[]

Live: Provider Lookup

Type a provider ID to inspect its config

Name: Gmail

Color: #EA4335

Regions: global

noBodyPreFill: false

Framework Wrappers

React

// SmartMailtoProvider wraps your app
<SmartMailtoProvider theme="dark" autoDetectGeo>
  <App />
</SmartMailtoProvider>

// useSmartMailto() for programmatic control
const { open, config } = useSmartMailto();
open('hello@example.com', { subject: 'Hi' });

// SmartMailto drop-in component replaces <a>
<SmartMailto href="mailto:hello@example.com" theme="dark">
  Contact Us
</SmartMailto>

Live: React Component

SmartMailto component with dark/light sync

Vue 3

// main.ts — register plugin
import { SmartMailtoPlugin } from '@smart-mailto/vue';
app.use(SmartMailtoPlugin, { theme: 'dark', autoDetectGeo: true });

// SmartMailto component (auto-registered)
<SmartMailto href="mailto:hello@example.com" theme="dark">
  Contact Us
</SmartMailto>

Svelte

// smartMailto action on any anchor
<a href="mailto:hello@example.com"
   use:smartMailto={{ theme: 'dark' }}>
  Contact Us
</a>

// Global init for full-page interception
import { initGlobal, destroyGlobal } from '@smart-mailto/svelte';
onMount(() => { initGlobal({ theme: 'dark' }); });
onDestroy(() => destroyGlobal());

Bundle & Performance

Bundle Size

< 8KB

gzipped, all targets

Enforced in CI via .github/workflows/bundle-size.yml

Modal Loading

Core bundle contains only parsing, resolution, and geo logic.

Modal UI + icons are dynamically imported on first trigger, keeping initial load minimal.

Build targets

ESM: dist/index.js
CJS: dist/index.cjs
Types: dist/index.d.ts