{"id":37217952,"url":"https://github.com/pennocktech/smtpdane","last_synced_at":"2026-01-15T01:04:29.990Z","repository":{"id":57527180,"uuid":"81719577","full_name":"PennockTech/smtpdane","owner":"PennockTech","description":"SMTP DANE testing tool","archived":false,"fork":false,"pushed_at":"2025-09-02T17:06:58.000Z","size":165,"stargazers_count":24,"open_issues_count":2,"forks_count":2,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-11-19T09:20:17.318Z","etag":null,"topics":["dane","dnssec","monitoring","nagios-plugin","ocsp","probe","smtp","smtp-client","tls","tlsa"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PennockTech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-02-12T10:55:21.000Z","updated_at":"2025-09-02T17:07:02.000Z","dependencies_parsed_at":"2022-09-07T02:10:45.508Z","dependency_job_id":"68915327-9b1e-4b90-a1b2-9348214bbebf","html_url":"https://github.com/PennockTech/smtpdane","commit_stats":{"total_commits":132,"total_committers":2,"mean_commits":66.0,"dds":0.06060606060606055,"last_synced_commit":"67e17874666393a8a180c75d5e13f9706f175988"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/PennockTech/smtpdane","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PennockTech%2Fsmtpdane","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PennockTech%2Fsmtpdane/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PennockTech%2Fsmtpdane/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PennockTech%2Fsmtpdane/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PennockTech","download_url":"https://codeload.github.com/PennockTech/smtpdane/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PennockTech%2Fsmtpdane/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28441011,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-15T00:55:22.719Z","status":"ssl_error","status_checked_at":"2026-01-15T00:55:20.945Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dane","dnssec","monitoring","nagios-plugin","ocsp","probe","smtp","smtp-client","tls","tlsa"],"created_at":"2026-01-15T01:04:29.241Z","updated_at":"2026-01-15T01:04:29.976Z","avatar_url":"https://github.com/PennockTech.png","language":"Go","readme":"smtpdane\n========\n\n[![Continuous Integration](https://github.com/PennockTech/smtpdane/actions/workflows/pushes.yaml/badge.svg)](https://github.com/PennockTech/smtpdane/actions/workflows/pushes.yaml)\n[![Coverage Status](https://coveralls.io/repos/github/PennockTech/smtpdane/badge.svg?branch=main)](https://coveralls.io/github/PennockTech/smtpdane?branch=main)\n\nSMTP Service monitoring of DANE-protected services, with optional\nNAGIOS-compatible behavior.\n\nA bit short on tests but has been used for a few years now and so far has both\nsucceeded when it should and failed when it should.\n\n---\n\n`go install go.pennock.tech/smtpdane@latest`  \n_(optional helpers documented below) (or use prebuilt binaries)_\n\nThis is an SMTP client which can connect to an SMTP server, issue `STARTTLS`\nand verify the certificate using DANE (TLSA records signed with DNSSEC).\nValidity of the certificate is checked, including date validity periods, but\nnot PKIX CA anchoring.\n\nPer [RFC7672][] we only support `DANE-TA(2)` and `DANE-EE(3)`;\n`PKIX-TA(0)` and `PKIX-EE(1)` are explicitly unsupported.\n\nThis relies upon a validating DNS resolver; we do not yet validate internally.\n(Most tools should not validate themselves, but perhaps a monitoring tool\nshould?)\n\nOptionally this client can speak TLS-on-connect instead of STARTTLS,\nfor [RFC8314][] `submissions` service (historically called `smtps` or\n`ssmtp`); this is port 465 mail service for clients to submit mail.\n\nThe tool will connect to each SMTP server specified, in parallel.  If there\nare multiple IP addresses, then each will be connected to, in parallel.\n\nFlags may be used to request looking up MX records or SRV records for a\ndomain.\n\n---\n\nBelow, find:\n * [Installation](#Installation) (binaries and from source)\n * [Invoking](#Invoking) (with [Examples](#Examples) available)\n * [Access needed](#Access-needed) to help with security sandboxing\n\n---\n\n## Installation\n\n### Binaries\n\nWe use [GoReleaser][] to make binaries\nautomatically, in GitHub CI, when a version tag is pushed.\n\nThe builds are reproducible, so that you can verify the builds yourself, if\ncomfortable with such flows.\n\nFind [the latest Release on GitHub](https://github.com/PennockTech/smtpdane/releases)\nfor pre-built binaries.\n\nWe're willing to add builds for other platforms, if there's interest.\nWe don't currently intend to offer OCI images for Container usage, because\nusing DNSSEC with DNS in Containers is less a scenario of \"there are corner\ncases\" and more \"how did you make something purely out of corners??\".\n\n\n### From Source\n\n#### Minimum Versions\n\nThis is free and open source software, offered to the public, and the\nmaintainers can make any changes to build dependencies, at any time, as they\ndeem fit.  But we will usually try to be a bit nicer than that.\n\nSo we reserve the right to, at any time and without notice, require a minimum\nversion of Go which is in the oldest release series supported by the Go\nlanguage maintainers.  Eg, if 1.21.x is the latest release then 1.20.x will\nstill be supported, so we can add dependencies which require 1.20.x to\ncompile.\n\n\nGo 1.14 or greater is required; the release of Go 1.15 changed how network\nerrors are returned in some situations; while we didn't happen to hit those,\nit's now just a matter of time before our situation breaks too, so switched to\nthe `errors.As()` replacement for interface casting, as introduced in Go 1.13.\nWe use `tls.CipherSuiteName()` from Go 1.14 for better diagnostics.\n\n( ~~Go 1.8 or greater is required.  We use the\n`crypto/tls.Config.VerifyPeerCertificate` callback introduced in that\nrelease.~~ )\n\n#### Process\n\nIf not cloned as a repo:\n\n```console\n$ go install go.pennock.tech/smtpdane@latest\n```\n\nIf cloned as a repo, so your shell cwd is inside this repo:\n\n```console\n$ go build .\n```\n\nOptionally, use `./.compile` instead of `go build` to embed extra repository\ninformation into the binary, but this is less necessary with Go Modules.\n\nWith that one `go install` command, assuming no other Go environment variables\nset up to move things from defaults, the binary can be found in\n`~/go/bin/smtpdane`.  If `$GOPATH` is set, then look in `bin/` inside the\nfirst directory in the list given by that variable.\n\nTo build as a static binary for deployment into a lib-less environment:\n\n```sh\n# the current VCS hosting service is subject to change:\ngit clone https://github.com/PennockTech/smtpdane\ncd smtpdane\n# simple\n./.compile static\n# manual:\ngo build -ldflags \"-linkmode external -extldflags -static\"\n```\n\nYou can instead use [GoReleaser][]:\n\n```sh\ngoreleaser build --snapshot --single-target --clean\n```\n\nAt this time there is no vendoring of dependencies.  If this matters in your\nenvironment, capture them for your use-cases.  If our dependency list grows to\ninclude packages with unstable APIs then this decision will be revisited.\n\nOur version numbering is semantic, with the caveat that Go only supports\nthe latest two minor versions of the toolsuite, and PennockTech does not\nconsider it a breaking change to add a dependency upon a stdlib feature which\nis present in all releases of Go which are currently supported by the Go\nlanguage maintainers.\n\n\n## Invoking\n\nInvoke with `-help` to see help output listing known flags and defaults.  \nSee the examples below which make it clear how simple it normally is.\n\nMost commonly: `smtpdane -mx my-domain.example.org`\n\nThe host to connect to is provided as a list of one or more hosts after any\noptions.\n\nUse `-port` to specify a different port to speak on, for each host which\ndoesn't specify a specific port.\nNote that `-port` specifies a default; if looking up SRV records, ports from\nSRV override the `-port` option.  However, port overrides on the host (see\nbelow) override SRV.\n\nUse `-tls-on-connect` to immediately start TLS instead of negotiating.  \nUse `-mx` to indicate that names supplied are domain-names and MX records\nshould be looked up.  \nUse `-submission` to do the same but look up service `submission` SRV records,\ntypically used for port 587 service.  \nUse `-submissions` to do the same, looking up for `submissions` though and\nforcing on the `-tls-on-connect` option.\n\nThe port can be included with the host in the usual `:1234` suffix notation;\nif the host is an IPv6 address, either do not include a port or use the\notherwise-optional square-brackets, thus `[2001:db8::25]:1234`.\n\nA SOCKS5 proxy can be used for establishing TCP connections (but not, at this\ntime, for the DNS resolution).  Use the `-proxy-tcp` option to provide a\n`socks5://` URL for establishing the connections.\n\nBy default, the `EHLO` command will supply a hostname of `smtpdane.invalid`;\nuse the `-helo` flag to override that value.\n\nUse `-quiet` (or `-q`) to not emit any messages unless there's a failure.  \nUse `-terse` to shorten the amount of output text.  \nUse `-nagios` to use Nagios exit codes (and be `-terse` \u0026 `-nocolor`).\n\nThe `-quiet` approach is suitable for cron jobs which should only emit when\nthere's a problem.  The `-nagios` approach is better for less ad-hoc\nmonitoring.  We're open to supporting other output formats for other\nmonitoring systems.\n\n### Examples\n\n```sh\n# Regular lookup of a host; check every address-record:\nsmtpdane mx1.example.org\n\n# Regular lookup of a domain; check every MX, every address:\nsmtpdane -mx example.org\n\n# Be invoked for Nagios monitoring, with terse output, no color codes,\n# avoiding stderr, but checking for OCSP (\u0026 DANE) on all MX servers\nsmtpdane -nagios -expect-ocsp -mx example.org\n\n# Regular lookup of SMTP Submission for a domain:\nsmtpdane -submission example.org\n\n# Regular lookup of SMTP Submissions TLS-on-connect for a domain:\nsmtpdane -submissions example.org\n\n# Connect to port 26 for a server, IPv4-only:\nsmtpdane -4 -port 26 mx1.example.org\n\n# Check if there is a Submissions (TLS-on-connect, 465) service on\n# each IP found for Submission service (587) to confirm that you're\n# good to add the newer _submissions._tcp SRV records too:\nsmtpdane -tls-on-connect -submission example.org:465\n\n# When verifying the certificate, add a different allowed hostname\nsmtpdane -aka mail.example.net mail.example.org\n\n# See much more information about the certs\nsmtpdane -show-cert-info -mx example.org\n\n# See expiring certificates much sooner; alas, Golang duration parsing\n# maxes out in units of hours, so extend in shell;\n# 3 months of 31 days each, 24 hours per day, don't forget 'h' unit\nsmtpdane -expiration-warning $((3*31*24))h -mx example.org\n\n# Turn missing OCSP stapling information into an error\nsmtpdane -expect-ocsp -mx example.org\n\n# Establish a SOCKS5 proxy connection in one terminal\nssh -D 5678 external.host.example.net\n# Then use that proxy for the TCP connections\nsmtpdane -proxy-tcp socks5://localhost:5678 -mx example.org\n\n# Resolve using a different set of DNS resolvers;\n# one resolver using default port, one with a non-standard port:\nDNS_RESOLVER='192.0.2.53, 192.0.2.100:54' smtpdane -mx example.org\n```\n\nNote that the `-aka` names are added to the list of \"acceptable\" names; you'll\nsee each success/failure if you pay attention to the output, but as long as\n_one_ name succeeds, the probe of that `host:ip` will be deemed a success.\n\nThe expiration time of _all_ certificates in the validated chain is checked\nfor validity, unless `-expiration-warning 0s` is passed.\nThis examines the `NotAfter` time.  `NotBefore` is ignored.\nOnly the validated chains are examined, so multiple-chain presentations\nrequire more care to check each thoroughly (suggestions welcome).\nWhile a normal TLS client only checks the current time, smtpdane checks two\ntimes: it checks for outright expired certificates, treating those as errors,\nand it checks for \"expiring soon\" certificates, treating those as warnings.\nTo effectively only check for outright expiry, use `-expiration-warning 1ns`\nto shift the warning to be enabled with a 1 nanosecond warning period; this\nleaves warnings as technically possible, albeit somewhat unlikely.\n\nOCSP status is only reported if either `-show-cert-info` or\n`-expect-ocsp` is passed.  The latter will cause missing OCSP information to\nbe treated as an error, and present/good OCSP information to be shown in\ngreen.  Note that a `TryLater` response-code is treated as a warning.\n\nA simple invocation for a `crontab(5)` might be:\n\n```\n17 */3 * * * /home/myname/go/bin/smtpdane -q -expect-ocsp -mx example.org\n```\n\nThat will check every 3 hours, at 17 minutes past the hour, and check every IP\nfor every hostname returned by the MX records for the domain, checking\ncertificate validity with default notification periods, and declaring an\nabsence of OCSP information to be an error.  No output will be produced as\nlong as everything is fine, but there will be output if there are problems,\nand cron will send an email.\n\n\n## Access needed\n\nYou should be able to write a security sandbox profile to constrain this tool,\nbased upon the information here.  If it's not listed but is needed, then\nthat's a documentation bug, please report it.\n\n1. Network connectivity, outbound on port 53, UDP and TCP\n   + If `/etc/resolv.conf` or `DNS_RESOLVER` specifies another port, then that\n     port too\n   + If invoked with a hostname which dispatches to multicast DNS, then likely\n     port 5353\n2. Outbound TCP, on port 25 and any other ports required for monitoring SMTP.\n   (587 and 465 are common choices).\n   + Ports can be supplied on the command-line, or via SRV records if invoked\n     with `-srv`\n   + If using `-proxy-tcp` then access to whichever host/port is specified\n     there.\n3. Stdio, ability to write to stdout/stderr.\n4. `/etc/resolv.conf`\n   + If the `DNS_RESOLVER` environment variable is set, it's used for\n     resolution, but the libraries still load this file\n5. Read-only access to `$SSL_CERT_FILE` and `$SSL_CERT_DIR` locations, and if\n   neither of those is set then to a set of common locations for those files.\n   + Inhibit with `-nocertnames`\n6. Read-only access to `/etc/services`; on many OSes also `/etc/nsswitch.conf`\n   to handle indirection to that, and then if that's _not_ just the file, then\n   wherever else services are read from.  Sometimes other `/etc` files used\n   for DNS resolution.\n7. Usually some source of system entropy (`/dev/urandom`) if not available via\n   a system call.\n8. Any other common OS start-up files used even for statically linked files.\n   + Eg, `/etc/malloc.conf` on some OSes\n9. No other filesystem access should be required, if statically linked.\n   + otherwise, everything used by the dynamic loader too\n\n\n[RFC7672]: https://tools.ietf.org/html/rfc7672\n           \"SMTP Security via Opportunistic DNS-Based Authentication of Named Entities (DANE) Transport Layer Security (TLS)\"\n[RFC8314]: https://tools.ietf.org/html/rfc8314\n           \"Cleartext Considered Obsolete: Use of Transport Layer Security (TLS) for Email Submission and Access\"\n[GoReleaser]: https://github.com/goreleaser/goreleaser\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpennocktech%2Fsmtpdane","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpennocktech%2Fsmtpdane","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpennocktech%2Fsmtpdane/lists"}