send-email: dependency removal, cleanup, + small feature

12 messages, 5 authors, 2016-06-15 · open the first message on its own page

send-email: dependency removal, cleanup, + small feature

From: Eric Wong <hidden>
Date: 2016-06-15 22:42:22

1 - Change from Mail::Sendmail to Net::SMTP
2 - use built-in time() instead of /bin/date '+%s'
3 - lazy-load Email::Valid and make it optional
4 - add support for mutt aliases files

Patches 1 and 3 make git-send-email easily runnable with any
reasonable Perl installation.  2 is just a good idea.  4 makes
my life a lot easier.

-- 
Eric Wong

[PATCH 1/4] send-email: Change from Mail::Sendmail to Net::SMTP

From: Eric Wong <hidden>
Date: 2016-06-15 22:42:22

Net::SMTP is in the base Perl distribution, so users are more
likely to have it.  Net::SMTP also allows reusing the SMTP
connection, so sending multiple emails is faster.

Signed-off-by: Eric Wong <redacted>

---

 git-send-email.perl |   66 ++++++++++++++++++++++++++++++++-------------------
 1 files changed, 41 insertions(+), 25 deletions(-)

7155ae6e5f94a8fdf55f50029af27279dd36fd0a
diff --git a/git-send-email.perl b/git-send-email.perl
index b220d11..efaf457 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -19,11 +19,17 @@
 use strict;
 use warnings;
 use Term::ReadLine;
-use Mail::Sendmail qw(sendmail %mailcfg);
 use Getopt::Long;
 use Data::Dumper;
+use Net::SMTP;
 use Email::Valid;
 
+# most mail servers generate the Date: header, but not all...
+$ENV{LC_ALL} = 'C';
+use POSIX qw/strftime/;
+
+my $smtp;
+
 sub unique_email_list(@);
 sub cleanup_compose_files();
 
@@ -271,35 +277,45 @@ $cc = "";
 
 sub send_message
 {
-	my $to = join (", ", unique_email_list(@to));
-
-	%mail = (	To	=>	$to,
-			From	=>	$from,
-			CC	=>	$cc,
-			Subject	=>	$subject,
-			Message	=>	$message,
-			'Reply-to'	=>	$from,
-			'In-Reply-To'	=>	$reply_to,
-			'Message-ID'	=>	$message_id,
-			'X-Mailer'	=>	"git-send-email",
-		);
-
-	$mail{smtp} = $smtp_server;
-	$mailcfg{mime} = 0;
-
-	#print Data::Dumper->Dump([\%mail],[qw(*mail)]);
-
-	sendmail(%mail) or die $Mail::Sendmail::error;
+	my @recipients = unique_email_list(@to);
+	my $to = join (",\n\t", @recipients);
+	@recipients = unique_email_list(@recipients,@cc);
+	my $date = strftime('%a, %d %b %Y %H:%M:%S %z', localtime(time));
+
+	my $header = "From: $from
+To: $to
+Cc: $cc
+Subject: $subject
+Reply-To: $from
+Date: $date
+Message-Id: $message_id
+X-Mailer: git-send-email
+";
+	$header .= "In-Reply-To: $reply_to\n" if $reply_to;
+
+	$smtp ||= Net::SMTP->new( $smtp_server );
+	$smtp->mail( $from ) or die $smtp->message;
+	$smtp->to( @recipients ) or die $smtp->message;
+	$smtp->data or die $smtp->message;
+	$smtp->datasend("$header\n$message") or die $smtp->message;
+	$smtp->dataend() or die $smtp->message;
+	$smtp->ok or die "Failed to send $subject\n".$smtp->message;
 
 	if ($quiet) {
-		printf "Sent %s\n", $subject;
+		print "Sent $subject\n";
 	} else {
-		print "OK. Log says:\n", $Mail::Sendmail::log;
-		print "\n\n"
+		print "OK. Log says:
+Date: $date
+Server: $smtp_server Port: 25
+From: $from
+Subject: $subject
+Cc: $cc
+To: $to
+
+Result: ", $smtp->code, ' ', ($smtp->message =~ /\n([^\n]+\n)$/s), "\n";
 	}
 }
 
-
 $reply_to = $initial_reply_to;
 make_message_id();
 $subject = $initial_subject;
@@ -390,7 +406,7 @@ sub cleanup_compose_files() {
 
 }
 
-
+$smtp->quit if $smtp;
 
 sub unique_email_list(@) {
 	my %seen;
-- 
1.2.4.gb622a

[PATCH 4/4] send-email: add support for mutt aliases files

From: Eric Wong <hidden>
Date: 2016-06-15 22:42:22

I got rid of the Email::Valid dependency since writing
RFC-correct email addresses is probably not a problem for most
users.

In my experience, misspelled usernames are a much bigger
problem.  I am prone to doing things like leaving out the 'k' in
Junio's email address and other things that Email::Valid can't
catch.

Since I use mutt and the aliases file is pretty simple, I've
added basic support for mutt alias files.

To setup git-send-email to use a mutt aliases file for a repo,
do this:

  git-repo-config sendemail.muttaliases <mutt_alias_file_path>

More email clients/address book formats can easily be supported
in the future.

Signed-off-by: Eric Wong <redacted>

---

 git-send-email.perl |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)

8bc65d178dd755ecd1f3c038b975b9bbe58c1015
diff --git a/git-send-email.perl b/git-send-email.perl
index 73bba19..207b1fb 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -89,6 +89,15 @@ sub gitvar_ident {
 my ($author) = gitvar_ident('GIT_AUTHOR_IDENT');
 my ($committer) = gitvar_ident('GIT_COMMITTER_IDENT');
 
+my %aliases;
+if (my $mutt_aliases = `git-repo-config sendemail.muttaliases`) {
+    chomp $mutt_aliases;
+    open my $ma, '<', $mutt_aliases or die "opening $mutt_aliases: $!\n";
+    while (<$ma>) { if (/^alias\s+(\S+)\s+(.*)/) { $aliases{$1} = $2 } }
+    close $ma;
+}
+# aliases for more mail clients can be supported here:
+
 my $prompting = 0;
 if (!defined $from) {
 	$from = $author || $committer;
@@ -112,6 +121,9 @@ if (!@to) {
 	$prompting++;
 }
 
+@to = map { $aliases{$_} || $_ } @to;
+@initial_cc = map { $aliases{$_} || $_ } @initial_cc;
+
 if (!defined $initial_subject && $compose) {
 	do {
 		$_ = $term->readline("What subject should the emails start with? ",
-- 
1.2.4.gb622a

[PATCH 3/4] send-email: lazy-load Email::Valid and make it optional

From: Eric Wong <hidden>
Date: 2016-06-15 22:42:22

It's not installed on enough machines, and is overkill most of
the time.  We'll fallback to a very basic regexp (that is a
looser variant of what Email::Valid allows) just in case, but
nothing like the monster regexp Email::Valid has to offer :)

Signed-off-by: Eric Wong <redacted>

---

 git-send-email.perl |   16 +++++++++++++---
 1 files changed, 13 insertions(+), 3 deletions(-)

140eaf9b9d438ea489e6c72e2148feb3e355aea8
diff --git a/git-send-email.perl b/git-send-email.perl
index 5e08817..73bba19 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -22,12 +22,12 @@ use Term::ReadLine;
 use Getopt::Long;
 use Data::Dumper;
 use Net::SMTP;
-use Email::Valid;
 
 # most mail servers generate the Date: header, but not all...
 $ENV{LC_ALL} = 'C';
 use POSIX qw/strftime/;
 
+my $have_email_valid = eval { require Email::Valid or undef };
 my $smtp;
 
 sub unique_email_list(@);
@@ -250,6 +250,16 @@ EOT
 # Variables we set as part of the loop over files
 our ($message_id, $cc, %mail, $subject, $reply_to, $message);
 
+sub extract_valid_address {
+	my $address = shift;
+	if ($have_email_valid) {
+		return Email::Valid->address($address);
+	} else {
+		# less robust/correct than the monster regexp in Email::Valid,
+		# but still does a 99% job, and one less dependency
+		return ($address =~ /([^\"<>\s]+@[^<>\s]+)/);
+	}
+}
 
 # Usually don't need to change anything below here.
 
@@ -259,7 +269,7 @@ our ($message_id, $cc, %mail, $subject, 
 # 1 second since the last time we were called.
 
 # We'll setup a template for the message id, using the "from" address:
-my $message_id_from = Email::Valid->address($from);
+my $message_id_from = extract_valid_address($from);
 my $message_id_template = "<%s-git-send-email-$message_id_from>";
 
 sub make_message_id
@@ -412,7 +422,7 @@ sub unique_email_list(@) {
 	my @emails;
 
 	foreach my $entry (@_) {
-		my $clean = Email::Valid->address($entry);
+		my $clean = extract_valid_address($entry);
 		next if $seen{$clean}++;
 		push @emails, $entry;
 	}
-- 
1.2.4.gb622a

[PATCH 2/4] send-email: use built-in time() instead of /bin/date '+%s'

From: Eric Wong <hidden>
Date: 2016-06-15 22:42:22

Signed-off-by: Eric Wong <redacted>

---

 git-send-email.perl |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

079ce058710240643369589448660620cd925f5c
diff --git a/git-send-email.perl b/git-send-email.perl
index efaf457..5e08817 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -264,8 +264,7 @@ my $message_id_template = "<%s-git-send-
 
 sub make_message_id
 {
-	my $date = `date "+\%s"`;
-	chomp($date);
+	my $date = time;
 	my $pseudo_rand = int (rand(4200));
 	$message_id = sprintf $message_id_template, "$date$pseudo_rand";
 	#print "new message id = $message_id\n"; # Was useful for debugging
-- 
1.2.4.gb622a

Re: [PATCH 3/4] send-email: lazy-load Email::Valid and make it optional

From: Randal L. Schwartz <hidden>
Date: 2016-06-15 22:42:22

quoted
quoted
quoted
quoted
"Eric" == Eric Wong [off-list ref] writes:
Eric> +my $have_email_valid = eval { require Email::Valid or undef };

This is not necessary... if eval fails, it returns undef by definition.  Your
code presumes that the non-zero last-expression-evaluated of a require is also
returned from the require, which I believe is only accidentally true, although
the behavior may be recently documented and therefore promised.  (On perl 5.8,
it looks a bit fishy to me at a quick glance.)

My favorite idiom for a possibly failing eval-step is:

        my $can_I_do_this = eval { riskything; 1 };

If riskything fails, eval returns undef.  If it succeeds, it evaluates the 1,
and returns that.

-- 
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
[off-list ref] <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

Re: [PATCH 3/4] send-email: lazy-load Email::Valid and make it optional

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:42:22

Eric Wong [off-list ref] writes:
+my $have_email_valid = eval { require Email::Valid or undef };
Merlyn already commented on this and I'd appreciate this part to
be redone.

Re: [PATCH 1/4] send-email: Change from Mail::Sendmail to Net::SMTP

From: Ryan Anderson <hidden>
Date: 2016-06-15 22:42:22

On Sat, Mar 25, 2006 at 02:43:30AM -0800, Eric Wong wrote:
Net::SMTP is in the base Perl distribution, so users are more
likely to have it.  Net::SMTP also allows reusing the SMTP
connection, so sending multiple emails is faster.
Overall, I like this set of cleanups, just one thing struck me as,
"why?"
 	if ($quiet) {
-		printf "Sent %s\n", $subject;
+		print "Sent $subject\n";
This seems to be a pointless change, and actually, might be long-term
counterproductive.

Assumption: Eventually, we're going to want to internationalize git.

If that is true, we'll eventually do something like this to lines like
that:
	printf( gettext("Send %s\n"), $subject);

The alternative:
	print gettext("Send $subject\n");
does not work.

(The line that xgettext will see is 'Send $subject\n', but when the
program actually runs, gettext will see the interpolated version, which
fails.)

Internationalization may still be a ways off, but I think we're reaching
the point where it might be something we care to think about.

-- 

Ryan Anderson
  sometimes Pug Majere

[PATCH] send-email: lazy-load Email::Valid and make it optional

From: Eric Wong <hidden>
Date: 2016-06-15 22:42:22

It's not installed on enough machines, and is overkill most of
the time.  We'll fallback to a very basic regexp just in case,
but nothing like the monster regexp Email::Valid has to offer :)

Small cleanup from Merlyn.

Signed-off-by: Eric Wong <redacted>

---

 git-send-email.perl |   16 +++++++++++++---
 1 files changed, 13 insertions(+), 3 deletions(-)

3f09a822e3871eeae521da80c748602862fc52ce
diff --git a/git-send-email.perl b/git-send-email.perl
index 5e08817..7cbf11d 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -22,12 +22,12 @@ use Term::ReadLine;
 use Getopt::Long;
 use Data::Dumper;
 use Net::SMTP;
-use Email::Valid;
 
 # most mail servers generate the Date: header, but not all...
 $ENV{LC_ALL} = 'C';
 use POSIX qw/strftime/;
 
+my $have_email_valid = eval { require Email::Valid; 1 };
 my $smtp;
 
 sub unique_email_list(@);
@@ -250,6 +250,16 @@ EOT
 # Variables we set as part of the loop over files
 our ($message_id, $cc, %mail, $subject, $reply_to, $message);
 
+sub extract_valid_address {
+	my $address = shift;
+	if ($have_email_valid) {
+		return Email::Valid->address($address);
+	} else {
+		# less robust/correct than the monster regexp in Email::Valid,
+		# but still does a 99% job, and one less dependency
+		return ($address =~ /([^\"<>\s]+@[^<>\s]+)/);
+	}
+}
 
 # Usually don't need to change anything below here.
 
@@ -259,7 +269,7 @@ our ($message_id, $cc, %mail, $subject, 
 # 1 second since the last time we were called.
 
 # We'll setup a template for the message id, using the "from" address:
-my $message_id_from = Email::Valid->address($from);
+my $message_id_from = extract_valid_address($from);
 my $message_id_template = "<%s-git-send-email-$message_id_from>";
 
 sub make_message_id
@@ -412,7 +422,7 @@ sub unique_email_list(@) {
 	my @emails;
 
 	foreach my $entry (@_) {
-		my $clean = Email::Valid->address($entry);
+		my $clean = extract_valid_address($entry);
 		next if $seen{$clean}++;
 		push @emails, $entry;
 	}
-- 
1.2.4.gb622a

Re: [PATCH 1/4] send-email: Change from Mail::Sendmail to Net::SMTP

From: Eric Wong <hidden>
Date: 2016-06-15 22:42:22

Ryan Anderson [off-list ref] wrote:
On Sat, Mar 25, 2006 at 02:43:30AM -0800, Eric Wong wrote:
quoted
Net::SMTP is in the base Perl distribution, so users are more
likely to have it.  Net::SMTP also allows reusing the SMTP
connection, so sending multiple emails is faster.
Overall, I like this set of cleanups, just one thing struck me as,
"why?"
quoted
 	if ($quiet) {
-		printf "Sent %s\n", $subject;
+		print "Sent $subject\n";
This seems to be a pointless change, and actually, might be long-term
counterproductive.
Force of habit, I think.  I originally rewrote that portion but thought
I reverted it back to the way it was.  Besides, it's even slightly
faster this way :)  It could still be faster(!) if I just printed a list
(like below).
Assumption: Eventually, we're going to want to internationalize git.

If that is true, we'll eventually do something like this to lines like
that:
	printf( gettext("Send %s\n"), $subject);

The alternative:
	print gettext("Send $subject\n");
does not work.
print gettext('Send '),$subject,"\n";
(The line that xgettext will see is 'Send $subject\n', but when the
program actually runs, gettext will see the interpolated version, which
fails.)

Internationalization may still be a ways off, but I think we're reaching
the point where it might be something we care to think about.
-- 
Eric Wong

[PATCH] send-email: Change from Mail::Sendmail to Net::SMTP

From: Eric Wong <hidden>
Date: 2016-06-15 22:42:22

Net::SMTP is in the base Perl distribution, so users are more
likely to have it.  Net::SMTP also allows reusing the SMTP
connection, so sending multiple emails is faster.

Signed-off-by: Eric Wong <redacted>

---

 Notes: Reverted printf => print change from earlier.

 git-send-email.perl |   64 ++++++++++++++++++++++++++++++++-------------------
 1 files changed, 40 insertions(+), 24 deletions(-)

8d65a0a4121ade9f48f186d0dcf9f41adc62b22c
diff --git a/git-send-email.perl b/git-send-email.perl
index b220d11..25daf16 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -19,11 +19,17 @@
 use strict;
 use warnings;
 use Term::ReadLine;
-use Mail::Sendmail qw(sendmail %mailcfg);
 use Getopt::Long;
 use Data::Dumper;
+use Net::SMTP;
 use Email::Valid;
 
+# most mail servers generate the Date: header, but not all...
+$ENV{LC_ALL} = 'C';
+use POSIX qw/strftime/;
+
+my $smtp;
+
 sub unique_email_list(@);
 sub cleanup_compose_files();
 
@@ -271,35 +277,45 @@ $cc = "";
 
 sub send_message
 {
-	my $to = join (", ", unique_email_list(@to));
-
-	%mail = (	To	=>	$to,
-			From	=>	$from,
-			CC	=>	$cc,
-			Subject	=>	$subject,
-			Message	=>	$message,
-			'Reply-to'	=>	$from,
-			'In-Reply-To'	=>	$reply_to,
-			'Message-ID'	=>	$message_id,
-			'X-Mailer'	=>	"git-send-email",
-		);
-
-	$mail{smtp} = $smtp_server;
-	$mailcfg{mime} = 0;
-
-	#print Data::Dumper->Dump([\%mail],[qw(*mail)]);
-
-	sendmail(%mail) or die $Mail::Sendmail::error;
+	my @recipients = unique_email_list(@to);
+	my $to = join (",\n\t", @recipients);
+	@recipients = unique_email_list(@recipients,@cc);
+	my $date = strftime('%a, %d %b %Y %H:%M:%S %z', localtime(time));
+
+	my $header = "From: $from
+To: $to
+Cc: $cc
+Subject: $subject
+Reply-To: $from
+Date: $date
+Message-Id: $message_id
+X-Mailer: git-send-email
+";
+	$header .= "In-Reply-To: $reply_to\n" if $reply_to;
+
+	$smtp ||= Net::SMTP->new( $smtp_server );
+	$smtp->mail( $from ) or die $smtp->message;
+	$smtp->to( @recipients ) or die $smtp->message;
+	$smtp->data or die $smtp->message;
+	$smtp->datasend("$header\n$message") or die $smtp->message;
+	$smtp->dataend() or die $smtp->message;
+	$smtp->ok or die "Failed to send $subject\n".$smtp->message;
 
 	if ($quiet) {
 		printf "Sent %s\n", $subject;
 	} else {
-		print "OK. Log says:\n", $Mail::Sendmail::log;
-		print "\n\n"
+		print "OK. Log says:
+Date: $date
+Server: $smtp_server Port: 25
+From: $from
+Subject: $subject
+Cc: $cc
+To: $to
+
+Result: ", $smtp->code, ' ', ($smtp->message =~ /\n([^\n]+\n)$/s), "\n";
 	}
 }
 
-
 $reply_to = $initial_reply_to;
 make_message_id();
 $subject = $initial_subject;
@@ -390,7 +406,7 @@ sub cleanup_compose_files() {
 
 }
 
-
+$smtp->quit if $smtp;
 
 sub unique_email_list(@) {
 	my %seen;
-- 
1.2.4.gb622a

Re: [PATCH] send-email: Change from Mail::Sendmail to Net::SMTP

From: Martin Langhoff <hidden>
Date: 2016-06-15 22:42:24

On 3/26/06, Eric Wong [off-list ref] wrote:
Net::SMTP is in the base Perl distribution, so users are more
likely to have it.  Net::SMTP also allows reusing the SMTP
connection, so sending multiple emails is faster.
This is causing problems for me on my Debian sarge dev box.

 * If I have to believe strace(), Net::SMTP is trying to look up
"localhost" via DNS. Sketchy workaround: use 127.0.0.1.

 * This box has nothing listening on port 25. It doesn't get email
from the net, being a LAN machine, so I've told the debian config
system that we don't need an smtp daemon. Net::SMTP doesn't know how
to use /usr/bin/sendmail

 * That nasty @@VERSION@@ thing isn't valid perl, so working on this
code is a pain. Something like this (warning! broken diff ahead!)
fixes it for me.
@@ -292,6 +292,11 @@ sub send_message
        @recipients = unique_email_list(@recipients,@cc);
        my $date = strftime('%a, %d %b %Y %H:%M:%S %z', localtime($time++));

+       my $gitversion = '@@GIT_VERSION@@';
+       if ($gitversion eq '@@'.'GIT_VERSION@@') {
+           $gitversion = `git --version`;
+       }
+
        my $header = "From: $from
 To: $to
 Cc: $cc
@@ -299,11 +304,11 @@ Subject: $subject
 Reply-To: $from
 Date: $date
 Message-Id: $message_id
-X-Mailer: git-send-email @@GIT_VERSION@@
+X-Mailer: git-send-email $gitversion
 ";
        $header .= "In-Reply-To: $reply_to\n" if $reply_to;
cheers,


martin
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help