{"thread":{"id":"63873","subject":"[PATCH] send-email: add --get-smtp-server option to fetch SMTP settings","startedAt":"2025-07-29T17:10:59Z","lastAt":"2025-07-30T15:14:40Z","messageCount":2,"participants":["Aditya Garg"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"522976","messageId":"PN3PR01MB9597763982F1AB6B5E5806CBB825A@PN3PR01MB9597.INDPRD01.PROD.OUTLOOK.COM","threadId":"63873","inReplyTo":null,"subject":"[PATCH] send-email: add --get-smtp-server option to fetch SMTP settings","fromName":"Aditya Garg","fromEmail":"gargaditya08@live.com","sentAt":"2025-07-29T17:10:32Z","receivedAt":"2025-07-29T17:10:59Z","isPatch":true,"sender":{"key":"gargaditya08@live.com","avatar":"https://avatars.githubusercontent.com/u/85610623?v=4"},"body":"Autoconfiguring SMTP server settings is a common feature present in many\nemail clients. In order to get the correct SMTP server settings easily,\nthis commit adds a `--get-smtp-server` option to `git send-email`. This\noption attempts to fetch the SMTP server settings for a given email address\nvia the following steps:\n\n1. It first tries to fetch the settings from Mozilla's ISPDB at\n   `https://autoconfig.thunderbird.net/v1.1/[domain]`.\n\n2. If that fails, it attempts to fetch the autoconfig file from the email\n   provider's autoconfig URL, which is typically in the format\n   `https://autoconfig.[domain]/mail/config-v1.1.xml?emailaddress=[email]`.\n\n3. If that also fails, it falls back to checking the MX records of the\n   domain used in the email address to find the SMTP server. It can be\n   useful in case of emails with custom domains. It attempts to guess\n   the correct domain for the email from the MX records, and repeats the\n   first 2 steps with the guessed domain.\n\nThis feature is heavily inpired by the autoconfig feature in Mozilla\nThunderbird. A detailed documentation about how thunderbird fetches the\nautoconfig settings can be found at:\n\nhttps://www.bucksch.org/1/projects/thunderbird/autoconfiguration/\n---\n Documentation/git-send-email.adoc |  55 ++++++++++-\n git-send-email.perl               | 153 +++++++++++++++++++++++++++++-\n 2 files changed, 205 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-send-email.adoc b/Documentation/git-send-email.adoc\nindex 5335502d68..d4fb761b4f 100644\n--- a/Documentation/git-send-email.adoc\n+++ b/Documentation/git-send-email.adoc\n@@ -13,6 +13,7 @@ SYNOPSIS\n 'git send-email' [<options>] <format-patch-options>\n 'git send-email' --dump-aliases\n 'git send-email' --translate-aliases\n+'git send-email' --get-smtp-server\n \n \n DESCRIPTION\n@@ -505,6 +506,15 @@ Information\n \taddress to standard output, one per line. See `sendemail.aliasFile`\n \tfor more information about aliases.\n \n+--get-smtp-server::\n+\tAttempt to get the correct SMTP server settings by entering an email\n+\taddress. Once an email address is entered, it will first try to get\n+\tthe correct settings from\n+\thttps://autoconfig.thunderbird.net/v1.1/[Mozilla's ISPDB], followed\n+\tby attempting to check for an autoconfig file hosted by the email\n+\tprovider, finally falling back to the MX records of the domain used\n+\tby the email address.\n+\n CONFIGURATION\n -------------\n \n@@ -512,6 +522,44 @@ include::includes/cmd-config-section-all.adoc[]\n \n include::config/sendemail.adoc[]\n \n+GETTING THE CORRECT SMTP SERVER SETTINGS\n+----------------------------------------\n+\n+You can attempt to get the correct SMTP server settings by using\n+the `--get-smtp-server` command line option with `git send-email`.\n+It will ask you for your email address, then attempt to get the\n+correct SMTP server settings for that email address. An email\n+address may have more than one configuration. In that case, any of\n+them can be used.\n+\n+For example, an output with email `someone@pobox.com` yields:\n+\n+----\n+Configuration 1:\n+  Server: smtp.pobox.com\n+  Port: 465\n+  Encryption: ssl\n+  Username: ssw@pobox.com\n+\n+Configuration 2:\n+  Server: smtp.pobox.com\n+  Port: 587\n+  Encryption: tls\n+  Username: ssw@pobox.com\n+----\n+\n+Here the value of:\n++\n+- `Server` corresponds to `sendmail.smtpServer`.\n+- `Port` corresponds to `sendmail.smtpServerPort`.\n+- `Encryption` corresponds to `sendmail.smtpEncryption`.\n+- `Username` corresponds to `sendmail.smtpUser`.\n++\n+\n+This method should work well for almost all large email providers in the\n+world. If it provides invalid settings or cannot retrieve them, contact\n+your email provider.\n+\n EXAMPLES OF SMTP SERVERS\n ------------------------\n Use Gmail as the SMTP Server\n@@ -624,8 +672,11 @@ https://metacpan.org/pod/Net::SMTP[Net::SMTP].\n \n These additional Perl modules are also required:\n \n-https://metacpan.org/pod/Authen::SASL[Authen::SASL] and\n-https://metacpan.org/pod/Mail::Address[Mail::Address].\n+https://metacpan.org/pod/Authen::SASL[Authen::SASL],\n+https://metacpan.org/pod/Mail::Address[Mail::Address],\n+https://metacpan.org/pod/Net::DNS[Net::DNS],\n+https://metacpan.org/pod/URI::Escape[URI::Escape] and\n+https://metacpan.org/dist/XML-LibXML[XML::LibXML].\n \n Exploiting the `sendmailCmd` option of `git send-email`\n ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 437f8ac46a..60bc1f2adb 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -32,6 +32,7 @@ sub usage {\n git send-email [<options>] <format-patch options>\n git send-email --dump-aliases\n git send-email --translate-aliases\n+git send-email --get-smtp-server\n \n   Composing:\n     --from                  <str>  * Email From:\n@@ -108,6 +109,7 @@ sub usage {\n                                      input according to the configured email\n                                      alias file(s), outputting the result to\n                                      standard output.\n+    --get-smtp-server              * Print the SMTP server settings for a given email.\n \n EOT\n \texit(1);\n@@ -222,6 +224,7 @@ sub format_2822_time {\n my $force = 0;\n my $dump_aliases = 0;\n my $translate_aliases = 0;\n+my $get_smtp_server = 0;\n \n # Variables to prevent short format-patch options from being captured\n # as abbreviated send-email options\n@@ -501,6 +504,15 @@ sub config_regexp {\n     if !$help and ($dump_aliases or $translate_aliases) and @ARGV;\n die __(\"--dump-aliases and --translate-aliases are mutually exclusive\\n\")\n     if !$help and $dump_aliases and $translate_aliases;\n+\n+my %get_smtp_server_options = (\n+\t\"get-smtp-server\" => \\$get_smtp_server,\n+);\n+$rc = GetOptions(%get_smtp_server_options);\n+usage() unless $rc;\n+die __(\"--get-smtp-server incompatible with other options\\n\")\n+\tif !$help and $get_smtp_server and @ARGV;\n+\n my %options = (\n \t\t    \"sender|from=s\" => \\$sender,\n \t\t    \"in-reply-to=s\" => \\$initial_in_reply_to,\n@@ -565,7 +577,7 @@ sub config_regexp {\n my @initial_bcc = @getopt_bcc ? @getopt_bcc : ($no_bcc ? () : @config_bcc);\n \n usage() if $help;\n-my %all_options = (%options, %dump_aliases_options, %identity_options);\n+my %all_options = (%options, %dump_aliases_options, %identity_options, %get_smtp_server_options);\n completion_helper(\\%all_options) if $git_completion_helper;\n unless ($rc) {\n     usage();\n@@ -757,6 +769,145 @@ sub parse_sendmail_aliases {\n \texit(0);\n }\n \n+sub fetch_config_mozilla_ispdb {\n+\tmy ($domain) = @_;\n+\tmy $ispdb_url = \"https://autoconfig.thunderbird.net/v1.1/$domain\";\n+\tmy $xml = fetch_config($ispdb_url);\n+\treturn $xml if $xml;\n+}\n+\n+sub fetch_config_domain_autoconfig {\n+\tmy ($domain, $email_enc) = @_;\n+\tmy $autoconfig_url = \"https://autoconfig.$domain/mail/config-v1.1.xml?emailaddress=$email_enc\";\n+\tmy $xml = fetch_config($autoconfig_url);\n+\treturn $xml if $xml;\n+}\n+\n+sub fetch_config {\n+\trequire HTTP::Tiny;\n+\tmy ($url) = @_;\n+\tmy $http = HTTP::Tiny->new(timeout => 10);\n+\tmy $res = $http->get($url);\n+\n+\treturn unless $res->{success};\n+\treturn $res->{content};\n+}\n+\n+sub extract_base_domain {\n+\trequire IO::Socket::SSL::PublicSuffix;\n+\tmy ($host) = @_;\n+\tmy $ps = IO::Socket::SSL::PublicSuffix->default;\n+\n+\tmy $public_suffix = $ps->public_suffix($host);\n+\treturn $host unless defined $public_suffix;\n+\n+\tmy @host_parts = split(/\\./, lc($host));\n+\tmy @suffix_parts = split(/\\./, $public_suffix);\n+\n+\t# Find where the suffix starts in the host\n+\tfor (my $i = 0; $i <= $#host_parts - $#suffix_parts; $i++) {\n+\t\tif (join('.', @host_parts[$i .. $#host_parts]) eq $public_suffix) {\n+\t\t\t# Precursor + suffix = base domain\n+\t\t\treturn join('.', $host_parts[$i - 1], @host_parts[$i .. $#host_parts]) if $i > 0;\n+\t\t\treturn $public_suffix;\n+\t\t}\n+\t}\n+\n+\treturn $host;\n+}\n+\n+sub get_mx_base_domain {\n+\trequire Net::DNS;\n+\tmy ($domain) = @_;\n+\tmy $resolver = Net::DNS::Resolver->new;\n+\tmy $query = $resolver->query($domain, \"MX\");\n+\n+\tif ($query) {\n+\t\tmy @mx_hosts = sort { $a->preference <=> $b->preference } grep { $_->type eq \"MX\" } $query->answer;\n+\t\tif (@mx_hosts) {\n+\t\t\tmy $mx_host = $mx_hosts[0]->exchange;\n+\t\t\t$mx_host =~ s/\\.$//;  # Remove trailing dot\n+\t\t\treturn extract_base_domain($mx_host);\n+\t\t}\n+\t}\n+\treturn;\n+}\n+\n+sub parse_config {\n+\trequire XML::LibXML;\n+\tmy ($xml, $email) = @_;\n+\tmy $parser = XML::LibXML->new;\n+\tmy $doc = eval { $parser->load_xml(string => $xml) };\n+\tdie \"Failed to parse XML\\n\" unless $doc;\n+\tmy $config_num = 0;\n+\tmy $smtp_encryption_config;\n+\tmy $smtp_user_config;\n+\n+\tforeach my $outgoing ($doc->findnodes('//outgoingServer')) {\n+\t\t$config_num++;\n+\t\tif ($outgoing->findvalue('./socketType') eq 'SSL') {\n+\t\t\t$smtp_encryption_config = 'ssl';\n+\t\t} elsif ($outgoing->findvalue('./socketType') eq 'STARTTLS') {\n+\t\t\t$smtp_encryption_config = 'tls';\n+\t\t} else {\n+\t\t\t$smtp_encryption_config = 'plain';\n+\t\t}\n+\n+\t\tif ($outgoing->findvalue('./username') eq '%EMAILADDRESS%') {\n+\t\t\t$smtp_user_config = $email;\n+\t\t} elsif ($outgoing->findvalue('./username') eq '%EMAILLOCALPART%') {\n+\t\t\t$smtp_user_config = (split /@/, $email)[0];\n+\t\t} elsif ($outgoing->findvalue('./username') eq '%EMAILDOMAIN%') {\n+\t\t\t$smtp_user_config = (split /@/, $email)[1];\n+\t\t} else {\n+\t\t\t$smtp_user_config = $outgoing->findvalue('./username');\n+\t\t}\n+\n+\t\tprint \"\\nConfiguration $config_num:\\n\";\n+\t\tprint \"  Server: \", $outgoing->findvalue('./hostname'), \"\\n\";\n+\t\tprint \"  Port: \", $outgoing->findvalue('./port'), \"\\n\";\n+\t\tprint \"  Encryption: \", $smtp_encryption_config, \"\\n\";\n+\t\tprint \"  Username: \", $smtp_user_config, \"\\n\";\n+\t}\n+}\n+\n+if ($get_smtp_server) {\n+\trequire URI::Escape;\n+\tprint \"Enter your email address: \";\n+\tchomp(my $email = <STDIN>);\n+\t$email =~ /@(.+)$/ or die \"Invalid email format.\\n\";\n+\tmy $domain = $1;\n+\tmy $email_enc = URI::Escape::uri_escape($email);\n+\n+\t# 1. Try Mozilla ISPDB\n+\tmy $xml = fetch_config_mozilla_ispdb($domain);\n+\n+\t# 2. Try domain autoconfig if ISPDB fails\n+\tif (!$xml) {\n+\t\t$xml = fetch_config_domain_autoconfig($domain, $email_enc);\n+\t}\n+\n+\t# 3. Try MX record lookup\n+\tif (!$xml) {\n+\t\tmy $base_domain = get_mx_base_domain($domain);\n+\t\tif ($base_domain && $base_domain ne $domain) {\n+\t\t\t$xml = fetch_config_mozilla_ispdb($base_domain);\n+\n+\t\t\tif (!$xml) {\n+\t\t\t\t$xml = fetch_config_domain_autoconfig($base_domain, $email_enc);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tif ($xml) {\n+\t\tprint \"\\nFound SMTP server settings for $email:\\n\";\n+\t\tparse_config($xml, $email);\n+\t} else {\n+\t\tprint \"\\nUnable to find SMTP server settings for $email\\n\";\n+\t}\n+\texit(0);\n+}\n+\n # is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if\n # $f is a revision list specification to be passed to format-patch.\n sub is_format_patch_arg {\n-- \n2.50.1.320.g2ad311502d\n\n"},{"id":"523010","messageId":"PN3PR01MB9597D7619BE1EA6E5630766BB824A@PN3PR01MB9597.INDPRD01.PROD.OUTLOOK.COM","threadId":"63873","inReplyTo":"PN3PR01MB9597763982F1AB6B5E5806CBB825A@PN3PR01MB9597.INDPRD01.PROD.OUTLOOK.COM","subject":"Re: [PATCH] send-email: add --get-smtp-server option to fetch SMTP settings","fromName":"Aditya Garg","fromEmail":"gargaditya08@live.com","sentAt":"2025-07-30T15:14:33Z","receivedAt":"2025-07-30T15:14:40Z","isPatch":true,"sender":{"key":"gargaditya08@live.com","avatar":"https://avatars.githubusercontent.com/u/85610623?v=4"},"body":"\n\nOn 29/07/25 10:40 pm, Aditya Garg wrote:\n> Autoconfiguring SMTP server settings is a common feature present in many\n> email clients. In order to get the correct SMTP server settings easily,\n> this commit adds a `--get-smtp-server` option to `git send-email`. This\n> option attempts to fetch the SMTP server settings for a given email address\n> via the following steps:\n> \n> 1. It first tries to fetch the settings from Mozilla's ISPDB at\n>    `https://autoconfig.thunderbird.net/v1.1/[domain]`.\n> \n> 2. If that fails, it attempts to fetch the autoconfig file from the email\n>    provider's autoconfig URL, which is typically in the format\n>    `https://autoconfig.[domain]/mail/config-v1.1.xml?emailaddress=[email]`.\n> \n> 3. If that also fails, it falls back to checking the MX records of the\n>    domain used in the email address to find the SMTP server. It can be\n>    useful in case of emails with custom domains. It attempts to guess\n>    the correct domain for the email from the MX records, and repeats the\n>    first 2 steps with the guessed domain.\n> \n> This feature is heavily inpired by the autoconfig feature in Mozilla\n> Thunderbird. A detailed documentation about how thunderbird fetches the\n> autoconfig settings can be found at:\n> \n> https://www.bucksch.org/1/projects/thunderbird/autoconfiguration/\n\nIt has a v2, which I didn't send as a reply to this by mistake:\n\nhttps://lore.kernel.org/git/20250730151227.12389-1-gargaditya08@live.com/T/#u\n\n"}]}