postalserver/postal · error · SocketError
'#{@host}' only resolves to addresses this server cannot rea
Error message
'#{@host}' only resolves to addresses this server cannot reach (#{addresses.join(', ')}) What it means
After the blocked-range check passes, AddressGuard filters resolved addresses to families this server can actually reach; if none remain it raises SocketError with the full address list. In practice this means the host resolved only to AAAA (IPv6) records while the Postal server has no IPv6 connectivity, so the request would be pinned to an unusable address.
Source
Thrown at lib/postal/http/address_guard.rb:123
# Reject the whole request if *any* resolved address is blocked. This is
# checked before the reachability filtering below so that a blocked
# destination is always reported as such, regardless of which address
# families this particular server can reach. It also defeats DNS
# responses that mix a public and a private address to slip past.
addresses.each do |address|
next unless blocked?(address)
raise BlockedDestinationError,
"Destination '#{@host}' (#{address}) is not permitted"
end
# Only connect to an address whose family this server can actually
# reach. Otherwise we might pin the connection to an IPv6 address on a
# host without IPv6 connectivity and fail to connect even when a usable
# IPv4 address was available.
usable = addresses.select { |address| family_reachable?(address) }
if usable.empty?
raise SocketError,
"'#{@host}' only resolves to addresses this server cannot reach " \
"(#{addresses.join(', ')})"
end
# Prefer IPv4 for predictability; only use IPv6 when it is the only
# reachable option.
(usable.find(&:ipv4?) || usable.first).to_s
end
private
# @return [Array<IPAddr>]
def resolve
return [IPAddr.new(@host)] if ip_literal?
Resolv.getaddresses(@host).filter_map do |address|
IPAddr.new(address)
rescue IPAddr::InvalidAddressErrorView on GitHub (pinned to d038eaa8c7)
Solutions
- Ask the endpoint host to publish an IPv4 A record and use that hostname
- Use an alternative hostname for the same service that still has an A record
- Enable working IPv6 on the Postal host (address, route, and DNS AAAA support in the container) so family_reachable? succeeds
- Put a dual-stack proxy in front of the v6-only service and point the endpoint at the proxy
Example fix
# before endpoint.url = "https://v6-only.example.com/hook" # resolves to AAAA only -> SocketError # after endpoint.url = "https://dual-stack.example.com/hook" # has an A record # verify from the Postal host: # dig A v6-only.example.com +short # empty dig A dual-stack.example.com +short # returns an IPv4 address
Defensive patterns
Strategy: validation
Validate before calling
# ensure the host has at least one IPv4 address before using it
ipv4 = Resolv::DNS.open { |dns| dns.getresources(host, Resolv::DNS::Resource::IN::A).map(&:address) }
raise ArgumentError, "#{host} has no IPv4 address and this server lacks IPv6" if ipv4.empty? && !Addrinfo.ip("::1").ipv6? && !ipv6_connectivity? Type guard
def reachable_address_family?(host)
require "resolv"
addrs = Resolv.getaddresses(host)
has_v4 = addrs.any? { |a| IPAddr.new(a).ipv4? }
# if only v6, verify this host actually has IPv6 connectivity
has_v4 || (addrs.any? && system("ping6 -c1 -W1 ::1 > /dev/null 2>&1") && ipv6_route_present?)
end Try / catch
begin Postal::HTTP.request(...) rescue SocketError => e # address-family problem: switch endpoint to a hostname with an A record # or enable IPv6 on this server; retrying unchanged will keep failing end
Prevention
- Prefer endpoint hostnames that publish both A and AAAA records
- Verify IPv6 connectivity of the Postal host (ip -6 route) before pointing it at v6-only services
- In Docker, enable IPv6 networking explicitly if v6-only targets are expected
- When a provider announces v6-only deprecation, update endpoint URLs before the A record disappears
When it happens
Trigger: An HTTPEndpoint/webhook hostname that is IPv6-only (AAAA records, no A record) called from a Postal host without working IPv6; or a host whose A record exists but whose family is unreachable in this environment (unusual routing setups, IPv6 disabled in the container).
Common situations: Modern domains that publish AAAA only; Docker/container deployments with IPv6 disabled while the target moved to v6-only; the endpoint provider deprecating its A record; cloud nodes without an assigned IPv6 address.
Related errors
- Could not resolve '#{@host}' to any IP address
- Destination '#{@host}' (#{address}) is not permitted
- No host was given for the request
- Error when scanning with rspamd (#{e.class})
- Invalid email address
AI-assisted analysis of postalserver/postal@d038eaa8c7 (2026-08-21).
Data as JSON: /api/errors/a0cdc202e60c6aec.
Report an issue: GitHub.