Gnus development mailing list
 help / color / Atom feed
* How to change from address while in message buffer?
@ 2020-01-06  9:57 Pankaj Jangid
  2020-01-06 21:42 ` dick.r.chiang
  2020-01-06 22:08 ` Malcolm Purvis
  0 siblings, 2 replies; 20+ messages in thread
From: Pankaj Jangid @ 2020-01-06  9:57 UTC (permalink / raw)
  To: ding

I am in message buffer composing an email. In this scenario, how can I
change the *From* header to something other than my default
user-mail-address.

I have configured MTA on the system to handle multiple SMTP accounts.

Regards
-- 
Pankaj Jangid





^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-06  9:57 How to change from address while in message buffer? Pankaj Jangid
@ 2020-01-06 21:42 ` dick.r.chiang
  2020-01-06 22:33   ` Eric Abrahamsen
                     ` (2 more replies)
  2020-01-06 22:08 ` Malcolm Purvis
  1 sibling, 3 replies; 20+ messages in thread
From: dick.r.chiang @ 2020-01-06 21:42 UTC (permalink / raw)
  To: Pankaj Jangid; +Cc: ding

PJ> how can I change the *From* header to something other than my default
PJ> user-mail-address.

Contextually setting the *From* header based on whichever imap account I was
reading from proved a fairly tough problem.  I eventually got it right, but
not before embarrassingly sending replies from my personal email address to my
professional one.

I am very curious how others deal with what must be a very common problem.

My soup-to-nuts email solution resides at
https://github.com/dickmao/gnus-imap-walkthrough and the 30 lines of elisp
that handle context-sensitive *From* are at
https://github.com/dickmao/gnus-imap-walkthrough/blob/c1246d335e7029f1ed4e4f3ae9db8f258748b791/dot.gnus#L16-L44

I suspect though that you're looking for a simpler solution.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-06  9:57 How to change from address while in message buffer? Pankaj Jangid
  2020-01-06 21:42 ` dick.r.chiang
@ 2020-01-06 22:08 ` Malcolm Purvis
  2020-01-07  6:38   ` Pankaj Jangid
  1 sibling, 1 reply; 20+ messages in thread
From: Malcolm Purvis @ 2020-01-06 22:08 UTC (permalink / raw)
  To: ding

 
> I am in message buffer composing an email. In this scenario, how 
> can I change the *From* header to something other than my 
> default user-mail-address.

The From header in the message buffer is just plain text, so in 
the worst case you can just manually change the address.

If you split your mail from different addresses into different 
groups (say home and work), then you can configure the variable 
gnus-posting-styles to set the default From address for each 
group, as well as signatures, outgoing SMTP server, etc.

Malcolm

-- 
          Malcolm Purvis <malcolm@purvis.id.au>



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-06 21:42 ` dick.r.chiang
@ 2020-01-06 22:33   ` Eric Abrahamsen
  2020-01-06 23:39     ` dick.r.chiang
  2020-01-07  6:28   ` Vincent Bernat
  2020-01-07  7:58   ` Vegard Vesterheim
  2 siblings, 1 reply; 20+ messages in thread
From: Eric Abrahamsen @ 2020-01-06 22:33 UTC (permalink / raw)
  To: dick.r.chiang; +Cc: Pankaj Jangid, ding

dick.r.chiang@gmail.com writes:

> PJ> how can I change the *From* header to something other than my default
> PJ> user-mail-address.
>
> Contextually setting the *From* header based on whichever imap account I was
> reading from proved a fairly tough problem.  I eventually got it right, but
> not before embarrassingly sending replies from my personal email address to my
> professional one.
>
> I am very curious how others deal with what must be a very common problem.
>
> My soup-to-nuts email solution resides at
> https://github.com/dickmao/gnus-imap-walkthrough and the 30 lines of elisp
> that handle context-sensitive *From* are at
> https://github.com/dickmao/gnus-imap-walkthrough/blob/c1246d335e7029f1ed4e4f3ae9db8f258748b791/dot.gnus#L16-L44
>
> I suspect though that you're looking for a simpler solution.

I'm almost certainly misunderstanding something here, but can't you do
this with posting styles? When I want to compose a message with a
certain set of styles (including the "From" header) I put point on the
group I want to use to trigger the styles, and use "C-u m" instead of
regular "m".

Admittedly, this is actually kind of annoying and I wish there were a
cleaner way of doing it. But it works just fine.

No?

Eric



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-06 22:33   ` Eric Abrahamsen
@ 2020-01-06 23:39     ` dick.r.chiang
  2020-01-07  4:12       ` Eric Abrahamsen
  0 siblings, 1 reply; 20+ messages in thread
From: dick.r.chiang @ 2020-01-06 23:39 UTC (permalink / raw)
  To: Eric Abrahamsen; +Cc: Pankaj Jangid, ding

EA> I'm almost certainly misunderstanding something here, but can't you do
EA> this with posting styles?

No, you're not missing anything.  I am generally one to first inspect the
`gnus-msg-mail` code before planning an attack, but I don't think I would have
associated a term as seemingly cosmetic as "posting style" with changing
fundamental mail headers. Such is the curse and blessing of cannibalizing
usenet nomenclature for mail.

My only consolation for reinventing the wheel is I save typing "C-u" when I "m".



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-06 23:39     ` dick.r.chiang
@ 2020-01-07  4:12       ` Eric Abrahamsen
  2020-01-07  6:29         ` Pankaj Jangid
  0 siblings, 1 reply; 20+ messages in thread
From: Eric Abrahamsen @ 2020-01-07  4:12 UTC (permalink / raw)
  To: dick.r.chiang; +Cc: Pankaj Jangid, ding


On 01/06/20 18:39 PM, dick.r.chiang@gmail.com wrote:
> EA> I'm almost certainly misunderstanding something here, but can't you do
> EA> this with posting styles?
>
> No, you're not missing anything.  I am generally one to first inspect the
> `gnus-msg-mail` code before planning an attack, but I don't think I would have
> associated a term as seemingly cosmetic as "posting style" with changing
> fundamental mail headers. Such is the curse and blessing of cannibalizing
> usenet nomenclature for mail.
>
> My only consolation for reinventing the wheel is I save typing "C-u" when I "m".

Yup, nothing about it is particularly intuitive, but it does work just fine.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-06 21:42 ` dick.r.chiang
  2020-01-06 22:33   ` Eric Abrahamsen
@ 2020-01-07  6:28   ` Vincent Bernat
  2020-01-09  1:55     ` 황병희
  2020-01-07  7:58   ` Vegard Vesterheim
  2 siblings, 1 reply; 20+ messages in thread
From: Vincent Bernat @ 2020-01-07  6:28 UTC (permalink / raw)
  To: dick.r.chiang; +Cc: Pankaj Jangid, ding

 ❦  6 janvier 2020 16:42 -05, dick.r.chiang@gmail.com:

> PJ> how can I change the *From* header to something other than my default
> PJ> user-mail-address.
>
> Contextually setting the *From* header based on whichever imap account I was
> reading from proved a fairly tough problem.  I eventually got it right, but
> not before embarrassingly sending replies from my personal email address to my
> professional one.
>
> I am very curious how others deal with what must be a very common
> problem.

I am using gnus-posting-styles along with gnus-identities:

https://github.com/vincentbernat/dot.emacs/blob/master/lisp/vbe-gnus-identities.el#L32-L91
-- 
Don't stop with your first draft.
            - The Elements of Programming Style (Kernighan & Plauger)



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-07  4:12       ` Eric Abrahamsen
@ 2020-01-07  6:29         ` Pankaj Jangid
  2020-01-07 17:32           ` If you read this instead of my name it worked for me
  2020-01-07 17:43           ` Eric Abrahamsen
  0 siblings, 2 replies; 20+ messages in thread
From: Pankaj Jangid @ 2020-01-07  6:29 UTC (permalink / raw)
  To: Eric Abrahamsen; +Cc: dick.r.chiang, ding

> On 01/06/20 18:39 PM, dick.r.chiang@gmail.com wrote:
>> EA> I'm almost certainly misunderstanding something here, but can't
>> EA> you do this with posting styles?
>>
>> No, you're not missing anything.  I am generally one to first inspect
>> the `gnus-msg-mail` code before planning an attack, but I don't think
>> I would have associated a term as seemingly cosmetic as "posting
>> style" with changing fundamental mail headers. Such is the curse and
>> blessing of cannibalizing usenet nomenclature for mail.
>>
>> My only consolation for reinventing the wheel is I save typing "C-u"
>> when I "m".

Probably I was less clear in explaining my problem. All of these
suggestions work before actually launching a new message buffer. What I
want is that I am already in an *unsent message* buffer, and now I want
to change the "From:" header value. Manually editing the value at the
top doesn't actually work.

Regards,
-- 
Pankaj Jangid



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-06 22:08 ` Malcolm Purvis
@ 2020-01-07  6:38   ` Pankaj Jangid
  2020-02-07 13:42     ` Helmut Waitzmann
  2020-02-07 22:09     ` Helmut Waitzmann
  0 siblings, 2 replies; 20+ messages in thread
From: Pankaj Jangid @ 2020-01-07  6:38 UTC (permalink / raw)
  To: Malcolm Purvis; +Cc: ding

Malcolm Purvis <malcolm@purvis.id.au> writes:
>> I am in message buffer composing an email. In this scenario, how can
>> I change the *From* header to something other than my default
>> user-mail-address.
>
> The From header in the message buffer is just plain text, so in the
> worst case you can just manually change the address.

I have tried this and embarrassed myself a couple of times by sending the
email via my personal email address instead of official.

> If you split your mail from different addresses into different groups
> (say home and work), then you can configure the variable
> gnus-posting-styles to set the default From address for each 
> group, as well as signatures, outgoing SMTP server, etc.

Yes. This works fine. I am using this. My only problem is when I am
already in *unsent message* buffer and want to change "From:" header
value.

Regards,
-- 
Pankaj Jangid



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-06 21:42 ` dick.r.chiang
  2020-01-06 22:33   ` Eric Abrahamsen
  2020-01-07  6:28   ` Vincent Bernat
@ 2020-01-07  7:58   ` Vegard Vesterheim
  2020-01-07 10:44     ` Pankaj Jangid
  2 siblings, 1 reply; 20+ messages in thread
From: Vegard Vesterheim @ 2020-01-07  7:58 UTC (permalink / raw)
  To: dick.r.chiang; +Cc: Pankaj Jangid, ding

On Mon, 06 Jan 2020 16:42:54 -0500 dick.r.chiang@gmail.com wrote:

> PJ> how can I change the *From* header to something other than my default
> PJ> user-mail-address.
>
> Contextually setting the *From* header based on whichever imap account I was
> reading from proved a fairly tough problem.  I eventually got it right, but
> not before embarrassingly sending replies from my personal email address to my
> professional one.
>
> I am very curious how others deal with what must be a very common
> problem.

https://www.emacswiki.org/emacs/GnusAlias

-- 
Vennlig hilsen/Best regards
Vegard Vesterheim
Senior Software engineer
+47 48 11 98 98
vegard.vesterheim@uninett.no



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-07  7:58   ` Vegard Vesterheim
@ 2020-01-07 10:44     ` Pankaj Jangid
  2020-01-07 11:41       ` Vegard Vesterheim
  0 siblings, 1 reply; 20+ messages in thread
From: Pankaj Jangid @ 2020-01-07 10:44 UTC (permalink / raw)
  To: Vegard Vesterheim; +Cc: dick.r.chiang, ding

>
> https://www.emacswiki.org/emacs/GnusAlias

Is this working? I tried it a couple of days back and again today after
your email. Something is definitely wrong with my setup if it is working
for others.

I've configured gnus-alias-identity-alist like this

#+BEGIN_SRC emacs-list
;; gnus-alias settings
(setq gnus-alias-identity-alist
      '(("opt"
         nil
         "Pankaj Jangid <pankaj.jangid@optimizory.com>"
         "Optimizory"
         nil nil nil)
	("gml"
         nil
         "Pankaj Jangid <pankaj.jangid@gmail.com>"
         nil nil nil nil)
	("j4d"
         nil
         "Pankaj Jangid <p4j@j4d.net>"
         "J4D Networks"
	 nil nil nil)))
#+END_SRC

In the group buffer I pressed m to create a new message. It picked my
default user-mail-address. Now when I invoked gnus-alias-select-identity
and selected 'opt' from above list, it shows that the From header is
replaced but MTA is trying to send email via different SMTP server where
the authentication obviously fails.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-07 10:44     ` Pankaj Jangid
@ 2020-01-07 11:41       ` Vegard Vesterheim
  2020-01-07 16:19         ` Pankaj Jangid
  0 siblings, 1 reply; 20+ messages in thread
From: Vegard Vesterheim @ 2020-01-07 11:41 UTC (permalink / raw)
  To: Pankaj Jangid; +Cc: dick.r.chiang, ding

On Tue, 7 Jan 2020 10:44:50 +0000 Pankaj Jangid <p4j@j4d.net> wrote:

> In the group buffer I pressed m to create a new message. It picked my
> default user-mail-address. Now when I invoked gnus-alias-select-identity
> and selected 'opt' from above list, it shows that the From header is
> replaced but MTA is trying to send email via different SMTP server where
> the authentication obviously fails.

If you want to use different SMTP methods for different identities, you
can insert the header "X-Message-SMTP-Method" like this:

(setq gnus-alias-identity-alist
      '(("opt"
         nil
         "Pankaj Jangid <pankaj.jangid@optimizory.com>"
         "Optimizory"
         nil nil nil)
	("gml"
         nil
         "Pankaj Jangid <pankaj.jangid@gmail.com>"
         nil nil nil nil)
	("j4d"
         nil
         "Pankaj Jangid <p4j@j4d.net>"
         "J4D Networks"
	 (("X-Message-SMTP-Method" . "smtp mysmtp.host.com 587 username")) nil nil)))

BTW: I have created a function for "cycling" through the identities
(with a keybinding). See https://github.com/vv3/gnus-alias

-- 
Vennlig hilsen/Best regards
Vegard Vesterheim
Senior Software engineer
+47 48 11 98 98
vegard.vesterheim@uninett.no



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-07 11:41       ` Vegard Vesterheim
@ 2020-01-07 16:19         ` Pankaj Jangid
  0 siblings, 0 replies; 20+ messages in thread
From: Pankaj Jangid @ 2020-01-07 16:19 UTC (permalink / raw)
  To: Vegard Vesterheim; +Cc: dick.r.chiang, ding

Vegard Vesterheim <vegard.vesterheim@uninett.no> writes:
> If you want to use different SMTP methods for different identities, you
> can insert the header "X-Message-SMTP-Method" like this:
>
> (setq gnus-alias-identity-alist
>       '(("opt"
>          nil
>          "Pankaj Jangid <pankaj.jangid@optimizory.com>"
>          "Optimizory"
>          nil nil nil)
> 	("gml"
>          nil
>          "Pankaj Jangid <pankaj.jangid@gmail.com>"
>          nil nil nil nil)
> 	("j4d"
>          nil
>          "Pankaj Jangid <p4j@j4d.net>"
>          "J4D Networks"
> 	 (("X-Message-SMTP-Method" . "smtp mysmtp.host.com 587 username")) nil nil)))

This isn't working for me. Let me explain my MTA configuration as
well. May be that give some more clue.

I have configured 'postfix' to send email via couple of SMTP servers:
- smtp.gmail.com 587
- smtp.office365.com 587
- smtp.zoho.com

I have a mapping to specify which mail-server to use for which
email-id. And corresponding credentials are saved in postfix
configuration.

Now in Gnus, when I press m to launch message buffer for a new message,
It starts with

From: p4j@j4d.net

This is my default user-mail-address in Gnus/Emacs configuration. Now
when I call gnus-alias-select-identity <RET> opt <RET> to select
pankaj.jangid@optimizory.com as "from" address, it fills the headers
correctly. But when I send email (C-c C-c), it uses the SMTP server
associated with p4j@j4d.net, which was the original "from" address.

X-Message-SMTP-Method works. But this asks me for the username password
etc. I want to use "sendmail" method. How to ask "sendmail" to use
correct mail-server?

When I launch message buffer from the respective group (pressing m key),
it works fine. It picks the right SMTP server.

Regards,
-- 
Pankaj Jangid



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-07  6:29         ` Pankaj Jangid
@ 2020-01-07 17:32           ` If you read this instead of my name it worked for me
  2020-01-07 17:43           ` Eric Abrahamsen
  1 sibling, 0 replies; 20+ messages in thread
From: If you read this instead of my name it worked for me @ 2020-01-07 17:32 UTC (permalink / raw)
  To: ding

Pankaj writes:

> What I want is that I am already in an *unsent message* buffer, and
> now I want to change the "From:" header value. Manually editing the
> value at the top doesn't actually work.

What happens when you do?


  Best regards,

    Adam

-- 
 "Look at that guy in those tight leather pants             Adam Sjøgren
  He can't sing and you can see he can't dance"        asjo@koldfront.dk




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-07  6:29         ` Pankaj Jangid
  2020-01-07 17:32           ` If you read this instead of my name it worked for me
@ 2020-01-07 17:43           ` Eric Abrahamsen
  1 sibling, 0 replies; 20+ messages in thread
From: Eric Abrahamsen @ 2020-01-07 17:43 UTC (permalink / raw)
  To: Pankaj Jangid; +Cc: dick.r.chiang, ding


On 01/07/20 06:29 AM, Pankaj Jangid wrote:
>> On 01/06/20 18:39 PM, dick.r.chiang@gmail.com wrote:
>>> EA> I'm almost certainly misunderstanding something here, but can't
>>> EA> you do this with posting styles?
>>>
>>> No, you're not missing anything.  I am generally one to first inspect
>>> the `gnus-msg-mail` code before planning an attack, but I don't think
>>> I would have associated a term as seemingly cosmetic as "posting
>>> style" with changing fundamental mail headers. Such is the curse and
>>> blessing of cannibalizing usenet nomenclature for mail.
>>>
>>> My only consolation for reinventing the wheel is I save typing "C-u"
>>> when I "m".
>
> Probably I was less clear in explaining my problem. All of these
> suggestions work before actually launching a new message buffer. What I
> want is that I am already in an *unsent message* buffer, and now I want
> to change the "From:" header value. Manually editing the value at the
> top doesn't actually work.

Oh, I see. Completion works for me in the "From:" header -- going to the
end of the address and hitting TAB cycles through my addresses -- but I
think that function is provided by my contact management package, not
message-mode. And it doesn't re-run posting styles (ie, nothing else in
the message buffer changes), and it would be nice if it did.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-07  6:28   ` Vincent Bernat
@ 2020-01-09  1:55     ` 황병희
  2020-01-10  5:59       ` Bob Newell
  0 siblings, 1 reply; 20+ messages in thread
From: 황병희 @ 2020-01-09  1:55 UTC (permalink / raw)
  To: The Gnus

Helllow Vincent^^^

Vincent Bernat <bernat@luffy.cx> writes:

>  ❦  6 janvier 2020 16:42 -05, dick.r.chiang@gmail.com:
>
>> PJ> how can I change the *From* header to something other than my default
>> PJ> user-mail-address.
>>
>> Contextually setting the *From* header based on whichever imap account I was
>> reading from proved a fairly tough problem.  I eventually got it right, but
>> not before embarrassingly sending replies from my personal email address to my
>> professional one.
>>
>> I am very curious how others deal with what must be a very common
>> problem.
>
> I am using gnus-posting-styles along with gnus-identities:
>
> https://github.com/vincentbernat/dot.emacs/blob/master/lisp/vbe-gnus-identities.el#L32-L91

One day ago, ding-owner@lists.math.uh.edu did moderate (*) my before mail so
i re-send mail. Vincent's code is somewhat graceful way i think so i
added it in my bookmark, thanks^^^

Sincerely, Gnus' fan Byung-Hee

(*) My Face header is too long thus my mail is trapped to spam lader, i guess.

-- 
^고맙습니다 _地平天成_ 감사합니다_^))//



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-09  1:55     ` 황병희
@ 2020-01-10  5:59       ` Bob Newell
  2020-01-18  1:59         ` 황병희
  0 siblings, 1 reply; 20+ messages in thread
From: Bob Newell @ 2020-01-10  5:59 UTC (permalink / raw)
  To: The Gnus

Aloha everyone,

At the risk of being a little repetitious, everything here can be set
up by using gnu-alias and assigning identities and rules to the
variables
gnus-alias-identity-alist (and gnus-alias-identity-rules if you want
to determine identity based on From, To, etc.).

Then call gnus-alias-select-identity, on my system bound to C-c C-p,
at any time while composing an email.

There are a few edge cases, especially when using both -alist and
-rules, but by and large it's smooth and straightforward (at least
straightforward by gnus' standard).

Bob Newell
Honolulu, Hawai`i



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-10  5:59       ` Bob Newell
@ 2020-01-18  1:59         ` 황병희
  0 siblings, 0 replies; 20+ messages in thread
From: 황병희 @ 2020-01-18  1:59 UTC (permalink / raw)
  To: ding

Hellow Bob^^^

Bob Newell <bobnewell@bobnewell.net> writes:

> Aloha everyone,
>
> At the risk of being a little repetitious, everything here can be set
> up by using gnu-alias and assigning identities and rules to the
> variables
> gnus-alias-identity-alist (and gnus-alias-identity-rules if you want
> to determine identity based on From, To, etc.).
>
> Then call gnus-alias-select-identity, on my system bound to C-c C-p,
> at any time while composing an email.
>
> There are a few edge cases, especially when using both -alist and
> -rules, but by and large it's smooth and straightforward (at least
> straightforward by gnus' standard).

Still i don't know about these features exactly because i have no skills
and background for Emacs lisp.

However,

If possible can, i would like to convert all to Python codes. 

ps. Gmane NNTP now OK^^^

Sincerely, Gnus fan Byung-Hee

-- 
^고맙습니다 _地平天成_ 감사합니다_^))//




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-07  6:38   ` Pankaj Jangid
@ 2020-02-07 13:42     ` Helmut Waitzmann
  2020-02-07 22:09     ` Helmut Waitzmann
  1 sibling, 0 replies; 20+ messages in thread
From: Helmut Waitzmann @ 2020-02-07 13:42 UTC (permalink / raw)
  To: ding

Pankaj Jangid <p4j@j4d.net>:
>Malcolm Purvis <malcolm@purvis.id.au> writes:

>> If you split your mail from different addresses into different
>> groups (say home and work), then you can configure the variable
>> gnus-posting-styles to set the default From address for each
>> group, as well as signatures, outgoing SMTP server, etc.
>
>Yes. This works fine. I am using this.

So do I.

>My only problem is when I am already in *unsent message* buffer
>and want to change "From:" header value.
>

Yes, that was my problem, too.  To get that problem solved, I
wrote a set of lisp functions and variables, that, when it comes
to send a message, look in the unsent message buffer for to
investigate which mail sending service – may it be SMTP or
sendmail – should be used and what parameters should be set.

They send mail via smtpmail or sendmail, depending on the message
header:

In the message buffer, the "X-My-MSA-Account" header field is
looked up, if present, else the "Sender" header field, if present,
else the "From" header field.  The e-mail-address in that header
field is extracted and used to determine the message submission
accounts for looking up the message submission configuration (see
variable my-messagesubmission-configuration) by using regular
expressions matching on the extracted e-mail address.

That configuration is then modified by the contents of the
"X-My-MSA-Configuration" header field (if present).  (This allows
to even change the configuration ad hoc in the message buffer.) 
According to the configuration, smtpmail or sendmail variables are
set.  Then the message is sent via the smtpmail or sendmail
mailers.

To install that library, I put the functions and variables into
the file "~/emacslisp/messagesubmission.el" (see below) – you are
free to choose a different name –, then byte-compiled it.

To make use of the library, I 'load' it from my emacs startup file
and set the variables 'message-send-mail-function' and
'send-mail-function' to the appropriate functions:

;;;;
;;;; This is to be part of the emacs startup file:
;;;;

;; Load the message submission service file:
(load "~/emacslisp/messagesubmission")
;; Note: There is no ".el" file name extension by intention.

;; Have the library hooked in.  This will activate it:

(setq-default
 message-send-mail-function
 (function my-messagesubmission-message-send-mail)
 send-mail-function
 (function my-messagesubmission-send-mail))

;; Configure the message submission variables:

(setq-default my-messagesubmission-debug nil)
;; Set it to 't' to have the configuration used when sending a message
;; logged in the "*Messages*" buffer.

(setq-default
 my-messagesubmission-configuration
 '(
   ;; If the originator address is someone at home, I'd like to use
   ;; sendmail:
   ;;
   (("@\\(?:[[:graph:]]+\\.\\)?at-home\\.example\\'" t)

    ;; Use sendmail for sending mail:
    ;;
    (send-mail-function sendmail-send-it)
    (message-send-mail-function message-send-mail-with-sendmail)

    ;; If sendmail-f is not evil, let the address to be used in the
    ;; MAIL FROM SMTP command be the address from which the message
    ;; pretends to originate.
    ;; Else compute the address by using the userid.
    ;;
    (message-sendmail-f-is-evil t))

   ;; I've got two mail accounts at the freemail provider
   ;; "freemail.example". This is the common part of its
   ;; configuration:
   ;;
   (("@freemail\\.example\\'" t)

    ;; Let gnus speak SMTP to the fremailer's SMTP server:
    ;;
    (send-mail-function smtpmail-send-it)
    (message-send-mail-function message-smtpmail-send-it)

    ;; This is the SMTP server:
    ;;
    (smtpmail-smtp-server "smtp.freemail.example")

    ;; Use STARTTLS:
    ;;
    (smtpmail-smtp-service 587)
    (clientcertfile nil)
    (clientkeyfile nil)
    (mail-specify-envelope-from t))

   ;; One of the two accounts at freemail.example:
   ;;
   (("\\`Helmut\\.Waitzmann@freemail\\.example\\'" t)
    (username "Helmut.Waitzmann")
    (password "secret")
    (mail-envelope-from "Helmut.Waitzmann@freemail.example"))

   ;; The other of the two accounts at freemail.example:
   ;;
   (("\\`Helmut\\.Waitzmann\\.nospam@freemail\\.example\\'" t)
    (username "Helmut.Waitzmann.nospam")
    (password "even more secret")
    (mail-envelope-from "Helmut.Waitzmann.nospam@freemail.example"))

   ;; At work, I'll use SMTP to submit a message:
   ;;
   (("\\`\\(waitzmann@at-work\\.example\\)\\'" t)
    (send-mail-function smtpmail-send-it)
    (message-send-mail-function message-smtpmail-send-it)
    (smtpmail-smtp-server "smtp.at-work.example")

    ;; STARTTLS
    ;;
    (smtpmail-smtp-service 25)
    (clientcertfile nil)
    (clientkeyfile nil)
    (username "waitzmann")

    ;; Ask me for the password:
    ;;
    (password nil)
    (mail-specify-envelope-from t)
    (mail-envelope-from "waitzmann@at-work.example"))))

(setq-default smtpmail-debug-info nil)
(setq-default smtpmail-debug-verb nil)

;;;;
;;;; This is the file "~/emacslisp/messagesubmission.el":
;;;;

(defconst my-messagesubmission-configuration-symbols
  (let ((configsymbols (make-vector 29 0)))
    (mapc
     (function
      (lambda (cons)
        (let
            ((symbol (my-car-strict cons))
             (predicate (my-cdr-strict cons))
             configsymbol)
          (unless (and symbol (symbolp symbol))
            ;; No non-nil symbol:
            (signal
             'wrong-type-argument
             (list
              (lambda (symbol) (and symbol (symbolp symbol)))
              symbol)))
          (unless (or (null predicate) (functionp predicate))
            (signal
             'wrong-type-argument
             (list
              (lambda (predicate)
                (or (null predicate) (functionp predicate)))
              predicate)))
          (setq configsymbol (intern (symbol-name symbol) configsymbols))
          (set configsymbol predicate))))
     (list
      ;; list of conses of each a configuration symbol and the predicate to be
      ;; satisfied.  Each list entry is a cons, the car of which is the
      ;; configuration symbol, and the cdr of which is
      ;; either nil: Then the configuration symbol shall be unbound.
      ;; or t: Then the configuration symbol may have a value of any kind.
      ;; or a predicate: Then the configuration symbol shall have a value
      ;;    that shall satisfy the predicate.
      (cons 'my-messagesubmission-debug 'booleanp)
      (cons 'smtpmail-debug-info (lambda (value) t))
      (cons 'smtpmail-debug-verb (lambda (value) t))
      (cons 'message-send-mail-function (lambda (value) t))
      (cons 'send-mail-function (lambda (value) t))
      (cons 'message-sendmail-f-is-evil (lambda (value) t))
      (cons 'message-sendmail-envelope-from
            (lambda (value) (or (null value) (eq value 'header))))
      (cons 'message-send-mail-partially-limit
            (lambda (value) (or (null value) (integerp value))))
      (cons 'message-interactive (lambda (value) t))
      (cons 'smtpmail-mail-address 'stringp)
      (cons 'smtpmail-smtp-server 'stringp)
      (cons
       'smtpmail-smtp-service
       (lambda (value) (or (stringp value) (integerp value))))
      (cons
       'smtpmail-auth-credentials
       (lambda (value)
	 (or
	  (stringp value)
	  (and (consp value)
	       (stringp (nth 0 value))
	       (integerp (nth 1 value))
	       (stringp (nth 2 value))
	       (let ((v (nth 3 value)))
		 (or (null v) (stringp v)))))))
      (cons
       'smtpmail-starttls-credentials
       (lambda (value)
	 (and (consp value)
	      (stringp (nth 0 value))
	      (integerp (nth 1 value))
	      (let ((v (nth 2 value)))
		(or (null v) (stringp v)))
	      (let ((v (nth 3 value)))
		(or (null v) (stringp v))))))
      (cons
       'username
       (lambda (value) (or (null value) (stringp value))))
      (cons
       'password
       (lambda (value) (or (null value) (stringp value))))
      (cons
       'clientkeyfile
       (lambda (value) (or (null value) (stringp value))))
      (cons
       'clientcertfile
       (lambda (value) (or (null value) (stringp value))))
      (cons 'starttls-use-gnutls 'booleanp)
      (cons 'starttls-gnutls-program 'stringp)
      (cons 'starttls-extra-arguments 'listp)
      (cons
       'smtpmail-local-domain
       (lambda (value) (or (null value) (stringp value))))
      (cons
       'smtpmail-sendto-domain
       (lambda (value) (or (null value) (stringp value))))
      (cons 'mail-specify-envelope-from 'booleanp)
      (cons 'mail-envelope-from (lambda (value) t))))
    configsymbols)
  "*obarray containing the symbols, the symbol-names of which denote
legal configuration variables which may be set in variable
my-messagesubmission-configuration.  Each symbol's symbol-value is
either nil: Then the configuration symbol shall be unbound.
or t: Then the configuration symbol may have a value of any kind.
or a predicate: Then the configuration symbol shall have a value
   that shall satisfy the predicate.")

(defvar my-messagesubmission-configuration
  nil
  "*List of message submission configurations parts.
Each element of this list is a (part of a) message submission
configuration.
Each message submission configuration part consists of
  * a regular expression matcher to match the message submission account of
    the message to be sent:  The regular expression matcher is
    * either a string. Then it is a case sensitive regular expression.
    * Or it is a list containing 2 elements:
      * 1st: a string: the regular expression to be matched
      * 2nd: a boolean: if non-nil, indicating, the matching should ignore
        case.
  * zero or more keyword assignments:  Each keyword assignment is a list:
    (keyword value).  The keywords, together with their value types are as
    follows:

    keyword                       | valuetype
    ------------------------------+----------------------------------------
    send-mail-function            | see variable send-mail-function
    message-send-mail-function    | see variable message-send-mail-function
    smtpmail-smtp-server          | string
    smtpmail-smtp-service         | integer or string, e.g. 587 or \"smtp\"
    username                      | string (or nil to be prompted for)
    password                      | string (or nil to be prompted for)
    clientkeyfile                 | string or nil (see below)
    clientcertfile                | string or nil (see below)

    Any variable that satisfies the predicate user-variable-p may be
    specified, too.  But be careful not to include user-variables of this
    package.

    smtpmail-smtp-server
      is the server to connect to.  Will be used to set the variable
      smtpmail-smtp-server.  Will also be used to set the variables
      smtpmail-auth-credentials and smtpmail-starttls-credentials.

    smtpmail-smtp-service
      is the port to connect to.  Will be used to set the variable
      smtpmail-smtp-service.  Will also be used to set the variables
      smtpmail-auth-credentials and smtpmail-starttls-credentials.

    username
      will be used to set the variable smtpmail-auth-credentials.

    password
      will be used to set the variable smtpmail-auth-credentials.

    clientkeyfile
      is the name of a file (maybe nil, if you do not wish to use client
      authentication), containing a client key.  Will be used to set the
      variable smtpmail-starttls-credentials.

    clientcertfile
      is the name of a file (maybe nil, if you do not wish to use client
      authentication), containing a client certificate.  Will be used to
      set the variable smtpmail-starttls-credentials.

    So each element might look like this example:
    \(
      (\"\\\\`me@domain\\\\.example\\\\'\" nil)
      (message-send-mail-function 'message-smtpmail-send-it)
      (send-mail-function 'smtpmail-send-it)
      (smtpmail-smtp-server \"mail.domain.example\")
      (smtpmail-smtp-service 587)
      (username \"me\") (password nil)
      (clientkeyfile \"keyfile\") (clientcertfile \"certfile\")
    )")

(defvar my-messagesubmission-debug nil
  "*If non-nil, prints the configuration via the function 'message'.")

(defun my-messagesubmission-send-mail nil
  "Send mail via variable send-mail-function.
This function simply calls
\(my-messagesubmission-send-mail-via 'send-mail-function)"
  (my-messagesubmission-send-mail-via 'send-mail-function))

(defun my-messagesubmission-message-send-mail nil
  "Send mail via variable message-send-mail-function.
This function simply calls
\(my-messagesubmission-send-mail-via 'message-send-mail-function)"
  (my-messagesubmission-send-mail-via 'message-send-mail-function))

(defun my-messagesubmission-send-mail-via (via)
  "Send mail via smtpmail or sendmail, depending on the message header.
In the message buffer, the \"X-My-MSA-Account\" header line is looked up,
if present, else the \"Sender\" header line, if present, else the \"From\"
header line.  The e-mail-address is extracted and used to determine the
message submission account for looking up the message submission
configuration (see variable my-messagesubmission-configuration).  That
configuration is modified by the contents of the \"X-My-MSA-Configuration\"
header line (if present).  According to the configuration, smtpmail or
sendmail variables are set.  Then the message is sent via the smtpmail or
sendmail mailers."
  (eval-when-compile (require 'smtpmail))
  (let*
      ((account (my-messagesubmission-account))
       (assignments (my-messagesubmission-X-My-MSA-Configuration))
       (newvars
        (my-messagesubmission-configuration-variables
         account
	 (append
	  my-messagesubmission-configuration
	  (list (cons '("" nil) assignments)))))
       (savedvars (make-vector (length newvars) 0)))
    ;; Store some symbols, which will be modified later, in newvars to have
    ;; them saved and restored (in case they aren't already there), too:
    (let ((symbols
           '(smtpmail-auth-credentials
             smtpmail-starttls-credentials
             message-send-mail-function
             send-mail-function)))
      (while symbols
        (intern (symbol-name (car symbols)) newvars)
        (setq symbols (cdr symbols))))
    ;; Save the current values:
    (my-utils-copy-symbol-values newvars obarray savedvars)
    (let
        (username
         password
         clientkeyfile
         clientcertfile)
      (let((symbols
            '(username password clientkeyfile clientcertfile)))
        (while symbols
          (makunbound (car symbols))
          (setq symbols (cdr symbols))))
      (unwind-protect
          (progn
            ;; Assign the new values:
            (my-utils-copy-symbol-values newvars newvars obarray)
	    (when (and (boundp 'smtpmail-smtp-server)
		       (boundp 'smtpmail-smtp-service))
	      (when (and (boundp 'username) (boundp 'password))
		(setq
		 smtpmail-auth-credentials
		 (list
		  (list smtpmail-smtp-server smtpmail-smtp-service
			username password))))
	      (when (and (boundp 'clientkeyfile) (boundp 'clientcertfile))
		(setq smtpmail-starttls-credentials
		      (list
		       (list smtpmail-smtp-server smtpmail-smtp-service
			     clientkeyfile clientcertfile)))))
	    (when my-messagesubmission-debug
	      (message
	       "\n%S(%S):\nmessagesubmission configuration for account\n%S:\n"
	       'my-messagesubmission-send-mail-via via account)
	      (mapc
	       (function
		(lambda (symbol)
		  (let ((var (intern-soft (symbol-name symbol))))
		    (when var
		      ;; There is a symbol var:
		      (if (boundp var)
			  ;; That symbol has got a symbol-value, i.e. it
			  ;; is a variable:
			  (message
			   " (setq %S '%S)" var (symbol-value var))
			;; That symbol has got no symbol-value:
			(message
			 " (makunbound '%S)" var))))))
	       (let (symbols)
		 (mapatoms
		  (function
		   (lambda (symbol)
		     (setq symbols (cons symbol symbols))))
		  newvars)
		 (sort
		  symbols
		  (function
		   (lambda (s1 s2)
		     (< (compare-strings
			 (symbol-name s1) 0 nil
			 (symbol-name s2) 0 nil)
			0)))))))
	    ;; Remove any "X-My-MSA-Account" and "X-My-MSA-Configuration"
	    ;; headers:
	    (let ((deactivate-mark deactivate-mark))
	      (save-excursion
		(save-restriction
		  (message-narrow-to-headers)
		  (message-remove-header
		   "^X-My-MSA-\\(?:Account\\|Configuration\\)[ \t]*:" t))))
            ;; Send the message:
            (funcall (symbol-value via)))
        ;; Restore the saved variables:
        (my-utils-copy-symbol-values newvars savedvars obarray)))))

(defun my-messagesubmission-configuration-variables (account configuration)
  "The assigned-to symbols from configuration.
The return value is an obarray containing the assigned-to symbols.
ACCOUNT (a string) is the name of the message submission account, the
entries of my-messagesubmission-configuration are matched with."
  (let
      ((assignments
        ;; the (keyword value) pairs in my-messagesubmission-configuration
        ;; matching the MSA-account
        (apply
         (function append)
         (mapcar
          (function
           (lambda (alistentry)
             (let ((regexpmatcher (car-safe alistentry))
                   regexp
                   case-fold-search)
               (if (consp regexpmatcher)
                   ;; then regexpmatcher should be a list consisting of 2
                   ;; elements:  The first element is a string, the regular
                   ;; expression.  The second element is a boolean value
                   ;; for case-fold-search: If it is not nil, the regular
                   ;; expression match should ignore case.
                   (progn
                     (setq
                      regexp (car regexpmatcher)
                      regexpmatcher (cdr regexpmatcher))
                     (unless (consp regexpmatcher)
                       ;; Malformed list: cdr of list is not a cons: Error.
                       (signal
                        'wrong-type-argument
                        (list 'consp regexpmatcher)))
                     ;; regexpmatcher is a cons.  It should be a
                     ;; one-element-list containing the value for
                     ;; case-fold-search:
                     (setq case-fold-search (car regexpmatcher))
                     ;; There shall be no further elements in the list:
                     (let ((tail (cdr regexpmatcher)))
                       (when tail
                         (error
                          "Surplus (=non-nil) tail of list: %S" tail))))
                 ;; else regexpmatcher should be the regular expression itself.
                 ;; Then case-fold-search remains nil.
                 (setq regexp regexpmatcher))
               (unless (stringp regexp)
                 (signal 'wrong-type-argument (list 'stringp regexp)))
               (and (string-match-p regexp account)
                    (let ((assignments (cdr-safe alistentry)))
                      (unless (listp assignments)
                        (signal
                         'wrong-type-argument (list 'listp assignments)))
                      assignments)))))
          configuration)))
       (newsymbols
        (make-vector (length my-messagesubmission-configuration-symbols) 0)))
    (while assignments
      (let* ((assignment (car assignments))
             ;; Each assignment shall be a non-empty list of 1 or 2
             ;; elements:
             ;;   1st element: the symbol.
             ;;   if 2nd element is available: the symbol's value,
	     ;;   if 2nd element is not available: the symbol's value is
	     ;;   void.
             ;; Otherwise: Error.
             (symbol (my-car-strict assignment))
             configsymbol)
        ;; Does the 1st list element denote a non-nil symbol?
        (unless (and symbol (symbolp symbol))
          ;; No non-nil symbol:
          (signal
           'wrong-type-argument
           (list
            (lambda (symbol) (and symbol (symbolp symbol)))
            symbol)))
        ;; Yes, the 1st list element denotes a non-nil symbol.
        ;; Is it a known configuration symbol?
	(let ((symbolname (symbol-name symbol)))
	  (cond
	   ((setq configsymbol
		  (intern-soft symbolname
			       my-messagesubmission-configuration-symbols)))
	   ;; Any user variables are permitted, too:
	   ((user-variable-p symbol)
	    (setq configsymbol (make-symbol symbolname))
	    (set configsymbol t))
	   (t
	    ;; This configuration symbol is unknown.
	    (error "%S is not a known configuration variable" symbol))))

        ;; Now, look at the rest of the assignment:
        (setq assignment (cdr assignment))
        ;; Depending on (symbol-value configsymbol), assignment either
        ;; may be an empty list, meaning: no assignment value, i.e. a
        ;; void variable.  Or it may be a one-element list, containing
        ;; the value.
	;; If (eq predicate nil), then there shall be no assignment value:
	;;    make the symbol unbound.
	;; If (eq predicate t), then there may be any optional assignment
	;;    value.
	;; Else there shall be an assignment value that satisfies
	;;    predicate.
        (let ((predicate (symbol-value configsymbol))
              (newsymbol (intern (symbol-name symbol) newsymbols)))
	  (cond
	   ((null assignment)
	    (unless (or (null predicate) (eq t predicate))
	      (error
	       "Missing value for the configuration variable %S"
	       newsymbol)))
	   ;; There is not an empty list (meaning: a void symbol).  So it
	   ;; should be a list of one element: the value to be assigned.
	   ((not (consp assignment))
	    ;; Malformed list: It is not a cons: Error.
	    (signal 'wrong-type-argument (list 'consp assignment)))
	   ;; It is a cons.  Value = (car assignment), whatever that is.
	   ;; Does the list continue after the value?
	   ((cdr assignment)
	    ;; Malformed list: more than one list element (the
	    ;; value).
	    (error "Surplus (=non-nil) tail of list: %S"
		   (cdr assignment)))
	   (t
	    ;; There is no surplus (=non-nil) tail of the list.  The list
	    ;; consists of one element, which is the value.
	    (let ((value (car assignment)))
	      (unless (or (eq predicate t) (funcall predicate value))
		(signal 'wrong-type-argument (list predicate value)))
	      (set newsymbol value))))))
      (setq assignments (cdr assignments)))
    newsymbols))

(defun my-messagesubmission-account nil
  "Get the MSA account info from \"X-My-MSA-Account\", \"Sender\", and \"From\".
These message headers are examined one after another in this sequence; and
the first of them, that exists, is used, to retrieve the message submission
account. The account info, e.g. e-mail-address, is extracted by the
function mail-extract-address-components."
  (let ((field
	 (let ((deactivate-mark deactivate-mark))
	   (save-excursion
	     (save-restriction
	       (message-narrow-to-headers)
	       (or (mail-fetch-field "X-My-MSA-Account" nil t)
		   (mail-fetch-field "Sender" nil t)
		   (mail-fetch-field "From" nil t)))))))
    (let ((addresses
	   (and field
		(mail-extract-address-components field t))))
      ;; Accept exactly one address only, not less or more:
      (let ((n (length addresses)))
	(if (equal n 1)
	    (cadar addresses)
	  (error
	   "There must be specified exactly one message submission account, not %S"
	   n)
	  )))))

(defun my-messagesubmission-X-My-MSA-Configuration nil
  "Get MSA configuration info from the \"X-My-MSA-Configuration\" header field.
The content of this message header is a list of keyword assignments like
those of the variable 'my-messagesubmission-configuration'.  For example,
there could be the header field
X-My-MSA-Configuration: ((smtpmail-smtp-server \"mail-provider.example\")
 (username \"me\"))"
  (let ((field
	 (let ((deactivate-mark deactivate-mark))
	   (save-excursion
	     (save-restriction
	       (message-narrow-to-headers)
	       (mail-fetch-field "X-My-MSA-Configuration" nil nil t))))))
    (let ((n (length field)))
      (cond
       ((equal n 0) nil)
       ((equal n 1) (read (car field)))
       (t
	(error
	 "In the message header field \"X-My-MSA-Configuration\",
there must be specified at most one list of message submission
configuration keyword assignments, not %S"
	 n))
	))))

(defun my-utils-copy-symbol-values
  (thevars From To)
  "For all THEVARS, copy a symbol-value from obarray FROM to obarray TO.
For each symbol in the obarray THEVARS, do the following:
  If there is a variable with the same name in FROM, intern a symbol with
  the same name into the obarray TO and assign it the symbol-value of the
  symbol in obarray FROM.
  If there is no variable with the same name in FROM, then, if there is a
  symbol with the same name in TO, make its symbol-value unbound.
The obarray TO is returned as the function's value."
  (mapatoms
   (cond
    ((eq thevars From)
     ;; Copy all variables in From, i.e. in the function in the
     ;; default case, below, there is (eq thevars From) and
     ;; (eq sourcesymbol symbol).
     (function
      (lambda (sourcesymbol)
	(let
	    ((symbolname (symbol-name sourcesymbol)))
	  (if (boundp sourcesymbol)
	      ;; Copy its value into a variable in the obarray To:
	      (set (intern symbolname To)
		   (symbol-value sourcesymbol))
	    ;; Else: If a destinationsymbol exists, make its value unbound:
	    (let ((destinationsymbol
		   (intern-soft symbolname To)))
	      (if destinationsymbol
		  (makunbound destinationsymbol))))))))
    ((eq thevars To)
     ;; Assign to all variables in To a value of the corresponding
     ;; symbol in From.  If the symbol in From does not exist
     ;; or has got no symbol-value, make the symbol in To unbound.
     (function
      (lambda (destinationsymbol)
	(let*
	    ((symbolname (symbol-name destinationsymbol))
	     (sourcesymbol
	      (intern-soft symbolname From)))
	  (if (and sourcesymbol (boundp sourcesymbol))
	      ;; sourcesymbol is a variable with the name of
	      ;; destinationsymbol. Copy its value into the variable in
	      ;; the obarray To:
	      (set destinationsymbol (symbol-value sourcesymbol))
	    ;; Else let the value of the corresponding variable in the
	    ;; obarray To be unbound.
	    (makunbound destinationsymbol))))))
    (t
     (function
      (lambda (symbol)
	(let*
	    ((symbolname (symbol-name symbol))
	     (sourcesymbol
	      (intern-soft symbolname From)))
	  (if (and sourcesymbol (boundp sourcesymbol))
	      ;; sourcesymbol is a variable with the name of
	      ;; symbol. Copy its value into a variable in the obarray
	      ;; To:
	      (set (intern symbolname To)
		   (symbol-value sourcesymbol))
	    ;; Else: If a destinationsymbol exists, make its value unbound:
	    (let ((destinationsymbol
		   (intern-soft symbolname To)))
	      (if destinationsymbol
		  (makunbound destinationsymbol)))))))))
   thevars))

(defun my-car-strict (cons)
  "signals error, iff cons is not a cons cell, else returns '(car cons)'."
  (if (consp cons)
      (car cons)
    (signal 'wrong-type-argument (list 'consp cons))))

(defun my-cdr-strict (cons)
  "signals error, iff cons is not a cons cell, else returns '(cdr cons)'."
  (if (consp cons)
      (cdr cons)
    (signal 'wrong-type-argument (list 'consp cons))))




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: How to change from address while in message buffer?
  2020-01-07  6:38   ` Pankaj Jangid
  2020-02-07 13:42     ` Helmut Waitzmann
@ 2020-02-07 22:09     ` Helmut Waitzmann
  1 sibling, 0 replies; 20+ messages in thread
From: Helmut Waitzmann @ 2020-02-07 22:09 UTC (permalink / raw)
  To: Pankaj Jangid; +Cc: Malcolm Purvis, ding

Pankaj Jangid <p4j@j4d.net>:
>Malcolm Purvis <malcolm@purvis.id.au> writes:

>> If you split your mail from different addresses into different
>> groups (say home and work), then you can configure the variable
>> gnus-posting-styles to set the default From address for each
>> group, as well as signatures, outgoing SMTP server, etc.
>
>Yes. This works fine. I am using this.

So do I.

>My only problem is when I am already in *unsent message* buffer
>and want to change "From:" header value.
>

Yes, that was my problem, too.

I wrote a set of lisp functions and variables, that, when it comes
to send a message, look in the unsent message buffer for to
investigate which mail sending service – may it be SMTP or
sendmail – should be used and what parameters should be set.

They send mail via smtpmail or sendmail, depending on the message
header:

In the message buffer, the "X-My-MSA-Account" header field is
looked up, if present, else the "Sender" header field, if present,
else the "From" header field.  The e-mail-address in that header
field is extracted and used to determine the message submission
accounts for looking up the message submission configuration (see
variable my-messagesubmission-configuration) by using regular
expressions matching on the extracted e-mail address.

That configuration is then modified by the contents of the
"X-My-MSA-Configuration" header field (if present).  (This allows
to even change the configuration ad hoc in the message buffer.) 
According to the configuration, smtpmail or sendmail variables are
set.  Then the message is sent via the smtpmail or sendmail
mailers.

To install that library, I put the functions and variables into
the file "~/emacslisp/messagesubmission.el" (see below) – you are
free to choose a different name –, then byte-compiled it.

To make use of the library, I 'load' it from my emacs startup file
and set the variables 'message-send-mail-function' and
'send-mail-function' to the appropriate functions:

;;;;
;;;; This is to be part of the emacs startup file:
;;;;

;; Load the message submission service file:
(load "~/emacslisp/messagesubmission")
;; Note: There is no ".el" file name extension by intention.

;; Have the library hooked in:

(setq-default
 message-send-mail-function
 (function my-messagesubmission-message-send-mail)
 send-mail-function
 (function my-messagesubmission-send-mail))

;; Configure the message submission variables:

(setq-default my-messagesubmission-debug nil)
;; Set it to 't' to have the configuration used when sending a message
;; logged in the "*Messages*" buffer.

(setq-default
 my-messagesubmission-configuration
 '(
   ;; If the originator address is someone at home, I'd like to use
   ;; sendmail:
   ;;
   (("@\\(?:[[:graph:]]+\\.\\)?at-home\\.example\\'" t)

    ;; Use sendmail for sending mail:
    ;;
    (send-mail-function sendmail-send-it)
    (message-send-mail-function message-send-mail-with-sendmail)

    ;; If sendmail-f is not evil, let the address to be used in the
    ;; MAIL FROM SMTP command be the address from which the message
    ;; pretends to originate.
    ;; Else compute the address by using the userid.
    ;;
    (message-sendmail-f-is-evil t))

   ;; I've got two mail accounts at the freemail provider
   ;; "freemail.example". This is the common part of its
   ;; configuration:
   ;;
   (("@freemail\\.example\\'" t)

    ;; Let gnus speak SMTP to the fremailer's SMTP server:
    ;;
    (send-mail-function smtpmail-send-it)
    (message-send-mail-function message-smtpmail-send-it)

    ;; This is the SMTP server:
    ;;
    (smtpmail-smtp-server "smtp.freemail.example")

    ;; Use STARTTLS:
    ;;
    (smtpmail-smtp-service 587)
    (clientcertfile nil)
    (clientkeyfile nil)
    (mail-specify-envelope-from t))

   ;; One of the two accounts at freemail.example:
   ;;
   (("\\`Helmut\\.Waitzmann@freemail\\.example\\'" t)
    (username "Helmut.Waitzmann")
    (password "secret")
    (mail-envelope-from "Helmut.Waitzmann@freemail.example"))

   ;; The other of the two accounts at freemail.example:
   ;;
   (("\\`Helmut\\.Waitzmann\\.nospam@freemail\\.example\\'" t)
    (username "Helmut.Waitzmann.nospam")
    (password "even more secret")
    (mail-envelope-from "Helmut.Waitzmann.nospam@freemail.example"))

   ;; At work, I'll use SMTP to submit a message:
   ;;
   (("\\`\\(waitzmann@at-work\\.example\\)\\'" t)
    (send-mail-function smtpmail-send-it)
    (message-send-mail-function message-smtpmail-send-it)
    (smtpmail-smtp-server "smtp.at-work.example")

    ;; STARTTLS
    ;;
    (smtpmail-smtp-service 25)
    (clientcertfile nil)
    (clientkeyfile nil)
    (username "waitzmann")

    ;; Ask me for the password:
    ;;
    (password nil)
    (mail-specify-envelope-from t)
    (mail-envelope-from "waitzmann@at-work.example"))))

(setq-default smtpmail-debug-info nil)
(setq-default smtpmail-debug-verb nil)

;;;;
;;;; This is the file "~/emacslisp/messagesubmission.el":
;;;;

(defconst my-messagesubmission-configuration-symbols
  (let ((configsymbols (make-vector 29 0)))
    (mapc
     (function
      (lambda (cons)
        (let
            ((symbol (my-car-strict cons))
             (predicate (my-cdr-strict cons))
             configsymbol)
          (unless (and symbol (symbolp symbol))
            ;; No non-nil symbol:
            (signal
             'wrong-type-argument
             (list
              (lambda (symbol) (and symbol (symbolp symbol)))
              symbol)))
          (unless (or (null predicate) (functionp predicate))
            (signal
             'wrong-type-argument
             (list
              (lambda (predicate)
                (or (null predicate) (functionp predicate)))
              predicate)))
          (setq configsymbol (intern (symbol-name symbol) configsymbols))
          (set configsymbol predicate))))
     (list
      ;; list of conses of each a configuration symbol and the predicate to be
      ;; satisfied.  Each list entry is a cons, the car of which is the
      ;; configuration symbol, and the cdr of which is
      ;; either nil: Then the configuration symbol shall be unbound.
      ;; or t: Then the configuration symbol may have a value of any kind.
      ;; or a predicate: Then the configuration symbol shall have a value
      ;;    that shall satisfy the predicate.
      (cons 'my-messagesubmission-debug 'booleanp)
      (cons 'smtpmail-debug-info (lambda (value) t))
      (cons 'smtpmail-debug-verb (lambda (value) t))
      (cons 'message-send-mail-function (lambda (value) t))
      (cons 'send-mail-function (lambda (value) t))
      (cons 'message-sendmail-f-is-evil (lambda (value) t))
      (cons 'message-sendmail-envelope-from
            (lambda (value) (or (null value) (eq value 'header))))
      (cons 'message-send-mail-partially-limit
            (lambda (value) (or (null value) (integerp value))))
      (cons 'message-interactive (lambda (value) t))
      (cons 'smtpmail-mail-address 'stringp)
      (cons 'smtpmail-smtp-server 'stringp)
      (cons
       'smtpmail-smtp-service
       (lambda (value) (or (stringp value) (integerp value))))
      (cons
       'smtpmail-auth-credentials
       (lambda (value)
	 (or
	  (stringp value)
	  (and (consp value)
	       (stringp (nth 0 value))
	       (integerp (nth 1 value))
	       (stringp (nth 2 value))
	       (let ((v (nth 3 value)))
		 (or (null v) (stringp v)))))))
      (cons
       'smtpmail-starttls-credentials
       (lambda (value)
	 (and (consp value)
	      (stringp (nth 0 value))
	      (integerp (nth 1 value))
	      (let ((v (nth 2 value)))
		(or (null v) (stringp v)))
	      (let ((v (nth 3 value)))
		(or (null v) (stringp v))))))
      (cons
       'username
       (lambda (value) (or (null value) (stringp value))))
      (cons
       'password
       (lambda (value) (or (null value) (stringp value))))
      (cons
       'clientkeyfile
       (lambda (value) (or (null value) (stringp value))))
      (cons
       'clientcertfile
       (lambda (value) (or (null value) (stringp value))))
      (cons 'starttls-use-gnutls 'booleanp)
      (cons 'starttls-gnutls-program 'stringp)
      (cons 'starttls-extra-arguments 'listp)
      (cons
       'smtpmail-local-domain
       (lambda (value) (or (null value) (stringp value))))
      (cons
       'smtpmail-sendto-domain
       (lambda (value) (or (null value) (stringp value))))
      (cons 'mail-specify-envelope-from 'booleanp)
      (cons 'mail-envelope-from (lambda (value) t))))
    configsymbols)
  "*obarray containing the symbols, the symbol-names of which denote
legal configuration variables which may be set in variable
my-messagesubmission-configuration.  Each symbol's symbol-value is
either nil: Then the configuration symbol shall be unbound.
or t: Then the configuration symbol may have a value of any kind.
or a predicate: Then the configuration symbol shall have a value
   that shall satisfy the predicate.")

(defvar my-messagesubmission-configuration
  nil
  "*List of message submission configurations parts.
Each element of this list is a (part of a) message submission
configuration.
Each message submission configuration part consists of
  * a regular expression matcher to match the message submission account of
    the message to be sent:  The regular expression matcher is
    * either a string. Then it is a case sensitive regular expression.
    * Or it is a list containing 2 elements:
      * 1st: a string: the regular expression to be matched
      * 2nd: a boolean: if non-nil, indicating, the matching should ignore
        case.
  * zero or more keyword assignments:  Each keyword assignment is a list:
    (keyword value).  The keywords, together with their value types are as
    follows:

    keyword                       | valuetype
    ------------------------------+----------------------------------------
    send-mail-function            | see variable send-mail-function
    message-send-mail-function    | see variable message-send-mail-function
    smtpmail-smtp-server          | string
    smtpmail-smtp-service         | integer or string, e.g. 587 or \"smtp\"
    username                      | string (or nil to be prompted for)
    password                      | string (or nil to be prompted for)
    clientkeyfile                 | string or nil (see below)
    clientcertfile                | string or nil (see below)

    Any variable that satisfies the predicate user-variable-p may be
    specified, too.  But be careful not to include user-variables of this
    package.

    smtpmail-smtp-server
      is the server to connect to.  Will be used to set the variable
      smtpmail-smtp-server.  Will also be used to set the variables
      smtpmail-auth-credentials and smtpmail-starttls-credentials.

    smtpmail-smtp-service
      is the port to connect to.  Will be used to set the variable
      smtpmail-smtp-service.  Will also be used to set the variables
      smtpmail-auth-credentials and smtpmail-starttls-credentials.

    username
      will be used to set the variable smtpmail-auth-credentials.

    password
      will be used to set the variable smtpmail-auth-credentials.

    clientkeyfile
      is the name of a file (maybe nil, if you do not wish to use client
      authentication), containing a client key.  Will be used to set the
      variable smtpmail-starttls-credentials.

    clientcertfile
      is the name of a file (maybe nil, if you do not wish to use client
      authentication), containing a client certificate.  Will be used to
      set the variable smtpmail-starttls-credentials.

    So each element might look like this example:
    \(
      (\"\\\\`me@domain\\\\.example\\\\'\" nil)
      (message-send-mail-function 'message-smtpmail-send-it)
      (send-mail-function 'smtpmail-send-it)
      (smtpmail-smtp-server \"mail.domain.example\")
      (smtpmail-smtp-service 587)
      (username \"me\") (password nil)
      (clientkeyfile \"keyfile\") (clientcertfile \"certfile\")
    )")

(defvar my-messagesubmission-debug nil
  "*If non-nil, prints the configuration via the function 'message'.")

(defun my-messagesubmission-send-mail nil
  "Send mail via variable send-mail-function.
This function simply calls
\(my-messagesubmission-send-mail-via 'send-mail-function)"
  (my-messagesubmission-send-mail-via 'send-mail-function))

(defun my-messagesubmission-message-send-mail nil
  "Send mail via variable message-send-mail-function.
This function simply calls
\(my-messagesubmission-send-mail-via 'message-send-mail-function)"
  (my-messagesubmission-send-mail-via 'message-send-mail-function))

(defun my-messagesubmission-send-mail-via (via)
  "Send mail via smtpmail or sendmail, depending on the message header.
In the message buffer, the \"X-My-MSA-Account\" header line is looked up,
if present, else the \"Sender\" header line, if present, else the \"From\"
header line.  The e-mail-address is extracted and used to determine the
message submission account for looking up the message submission
configuration (see variable my-messagesubmission-configuration).  That
configuration is modified by the contents of the \"X-My-MSA-Configuration\"
header line (if present).  According to the configuration, smtpmail or
sendmail variables are set.  Then the message is sent via the smtpmail or
sendmail mailers."
  (eval-when-compile (require 'smtpmail))
  (let*
      ((account (my-messagesubmission-account))
       (assignments (my-messagesubmission-X-My-MSA-Configuration))
       (newvars
        (my-messagesubmission-configuration-variables
         account
	 (append
	  my-messagesubmission-configuration
	  (list (cons '("" nil) assignments)))))
       (savedvars (make-vector (length newvars) 0)))
    ;; Store some symbols, which will be modified later, in newvars to have
    ;; them saved and restored (in case they aren't already there), too:
    (let ((symbols
           '(smtpmail-auth-credentials
             smtpmail-starttls-credentials
             message-send-mail-function
             send-mail-function)))
      (while symbols
        (intern (symbol-name (car symbols)) newvars)
        (setq symbols (cdr symbols))))
    ;; Save the current values:
    (my-utils-copy-symbol-values newvars obarray savedvars)
    (let
        (username
         password
         clientkeyfile
         clientcertfile)
      (let((symbols
            '(username password clientkeyfile clientcertfile)))
        (while symbols
          (makunbound (car symbols))
          (setq symbols (cdr symbols))))
      (unwind-protect
          (progn
            ;; Assign the new values:
            (my-utils-copy-symbol-values newvars newvars obarray)
	    (when (and (boundp 'smtpmail-smtp-server)
		       (boundp 'smtpmail-smtp-service))
	      (when (and (boundp 'username) (boundp 'password))
		(setq
		 smtpmail-auth-credentials
		 (list
		  (list smtpmail-smtp-server smtpmail-smtp-service
			username password))))
	      (when (and (boundp 'clientkeyfile) (boundp 'clientcertfile))
		(setq smtpmail-starttls-credentials
		      (list
		       (list smtpmail-smtp-server smtpmail-smtp-service
			     clientkeyfile clientcertfile)))))
	    (when my-messagesubmission-debug
	      (message
	       "\n%S(%S):\nmessagesubmission configuration for account\n%S:\n"
	       'my-messagesubmission-send-mail-via via account)
	      (mapc
	       (function
		(lambda (symbol)
		  (let ((var (intern-soft (symbol-name symbol))))
		    (when var
		      ;; There is a symbol var:
		      (if (boundp var)
			  ;; That symbol has got a symbol-value, i.e. it
			  ;; is a variable:
			  (message
			   " (setq %S '%S)" var (symbol-value var))
			;; That symbol has got no symbol-value:
			(message
			 " (makunbound '%S)" var))))))
	       (let (symbols)
		 (mapatoms
		  (function
		   (lambda (symbol)
		     (setq symbols (cons symbol symbols))))
		  newvars)
		 (sort
		  symbols
		  (function
		   (lambda (s1 s2)
		     (< (compare-strings
			 (symbol-name s1) 0 nil
			 (symbol-name s2) 0 nil)
			0)))))))
	    ;; Remove any "X-My-MSA-Account" and "X-My-MSA-Configuration"
	    ;; headers:
	    (let ((deactivate-mark deactivate-mark))
	      (save-excursion
		(save-restriction
		  (message-narrow-to-headers)
		  (message-remove-header
		   "^X-My-MSA-\\(?:Account\\|Configuration\\)[ \t]*:" t))))
            ;; Send the message:
            (funcall (symbol-value via)))
        ;; Restore the saved variables:
        (my-utils-copy-symbol-values newvars savedvars obarray)))))

(defun my-messagesubmission-configuration-variables (account configuration)
  "The assigned-to symbols from configuration.
The return value is an obarray containing the assigned-to symbols.
ACCOUNT (a string) is the name of the message submission account, the
entries of my-messagesubmission-configuration are matched with."
  (let
      ((assignments
        ;; the (keyword value) pairs in my-messagesubmission-configuration
        ;; matching the MSA-account
        (apply
         (function append)
         (mapcar
          (function
           (lambda (alistentry)
             (let ((regexpmatcher (car-safe alistentry))
                   regexp
                   case-fold-search)
               (if (consp regexpmatcher)
                   ;; then regexpmatcher should be a list consisting of 2
                   ;; elements:  The first element is a string, the regular
                   ;; expression.  The second element is a boolean value
                   ;; for case-fold-search: If it is not nil, the regular
                   ;; expression match should ignore case.
                   (progn
                     (setq
                      regexp (car regexpmatcher)
                      regexpmatcher (cdr regexpmatcher))
                     (unless (consp regexpmatcher)
                       ;; Malformed list: cdr of list is not a cons: Error.
                       (signal
                        'wrong-type-argument
                        (list 'consp regexpmatcher)))
                     ;; regexpmatcher is a cons.  It should be a
                     ;; one-element-list containing the value for
                     ;; case-fold-search:
                     (setq case-fold-search (car regexpmatcher))
                     ;; There shall be no further elements in the list:
                     (let ((tail (cdr regexpmatcher)))
                       (when tail
                         (error
                          "Surplus (=non-nil) tail of list: %S" tail))))
                 ;; else regexpmatcher should be the regular expression itself.
                 ;; Then case-fold-search remains nil.
                 (setq regexp regexpmatcher))
               (unless (stringp regexp)
                 (signal 'wrong-type-argument (list 'stringp regexp)))
               (and (string-match-p regexp account)
                    (let ((assignments (cdr-safe alistentry)))
                      (unless (listp assignments)
                        (signal
                         'wrong-type-argument (list 'listp assignments)))
                      assignments)))))
          configuration)))
       (newsymbols
        (make-vector (length my-messagesubmission-configuration-symbols) 0)))
    (while assignments
      (let* ((assignment (car assignments))
             ;; Each assignment shall be a non-empty list of 1 or 2
             ;; elements:
             ;;   1st element: the symbol.
             ;;   if 2nd element is available: the symbol's value,
	     ;;   if 2nd element is not available: the symbol's value is
	     ;;   void.
             ;; Otherwise: Error.
             (symbol (my-car-strict assignment))
             configsymbol)
        ;; Does the 1st list element denote a non-nil symbol?
        (unless (and symbol (symbolp symbol))
          ;; No non-nil symbol:
          (signal
           'wrong-type-argument
           (list
            (lambda (symbol) (and symbol (symbolp symbol)))
            symbol)))
        ;; Yes, the 1st list element denotes a non-nil symbol.
        ;; Is it a known configuration symbol?
	(let ((symbolname (symbol-name symbol)))
	  (cond
	   ((setq configsymbol
		  (intern-soft symbolname
			       my-messagesubmission-configuration-symbols)))
	   ;; Any user variables are permitted, too:
	   ((user-variable-p symbol)
	    (setq configsymbol (make-symbol symbolname))
	    (set configsymbol t))
	   (t
	    ;; This configuration symbol is unknown.
	    (error "%S is not a known configuration variable" symbol))))

        ;; Now, look at the rest of the assignment:
        (setq assignment (cdr assignment))
        ;; Depending on (symbol-value configsymbol), assignment either
        ;; may be an empty list, meaning: no assignment value, i.e. a
        ;; void variable.  Or it may be a one-element list, containing
        ;; the value.
	;; If (eq predicate nil), then there shall be no assignment value:
	;;    make the symbol unbound.
	;; If (eq predicate t), then there may be any optional assignment
	;;    value.
	;; Else there shall be an assignment value that satisfies
	;;    predicate.
        (let ((predicate (symbol-value configsymbol))
              (newsymbol (intern (symbol-name symbol) newsymbols)))
	  (cond
	   ((null assignment)
	    (unless (or (null predicate) (eq t predicate))
	      (error
	       "Missing value for the configuration variable %S"
	       newsymbol)))
	   ;; There is not an empty list (meaning: a void symbol).  So it
	   ;; should be a list of one element: the value to be assigned.
	   ((not (consp assignment))
	    ;; Malformed list: It is not a cons: Error.
	    (signal 'wrong-type-argument (list 'consp assignment)))
	   ;; It is a cons.  Value = (car assignment), whatever that is.
	   ;; Does the list continue after the value?
	   ((cdr assignment)
	    ;; Malformed list: more than one list element (the
	    ;; value).
	    (error "Surplus (=non-nil) tail of list: %S"
		   (cdr assignment)))
	   (t
	    ;; There is no surplus (=non-nil) tail of the list.  The list
	    ;; consists of one element, which is the value.
	    (let ((value (car assignment)))
	      (unless (or (eq predicate t) (funcall predicate value))
		(signal 'wrong-type-argument (list predicate value)))
	      (set newsymbol value))))))
      (setq assignments (cdr assignments)))
    newsymbols))

(defun my-messagesubmission-account nil
  "Get the MSA account info from \"X-My-MSA-Account\", \"Sender\", and \"From\".
These message headers are examined one after another in this sequence; and
the first of them, that exists, is used, to retrieve the message submission
account. The account info, e.g. e-mail-address, is extracted by the
function mail-extract-address-components."
  (let ((field
	 (let ((deactivate-mark deactivate-mark))
	   (save-excursion
	     (save-restriction
	       (message-narrow-to-headers)
	       (or (mail-fetch-field "X-My-MSA-Account" nil t)
		   (mail-fetch-field "Sender" nil t)
		   (mail-fetch-field "From" nil t)))))))
    (let ((addresses
	   (and field
		(mail-extract-address-components field t))))
      ;; Accept exactly one address only, not less or more:
      (let ((n (length addresses)))
	(if (equal n 1)
	    (cadar addresses)
	  (error
	   "There must be specified exactly one message submission account, not %S"
	   n)
	  )))))

(defun my-messagesubmission-X-My-MSA-Configuration nil
  "Get MSA configuration info from the \"X-My-MSA-Configuration\" header field.
The content of this message header is a list of keyword assignments like
those of the variable 'my-messagesubmission-configuration'.  For example,
there could be the header field
X-My-MSA-Configuration: ((smtpmail-smtp-server \"mail-provider.example\")
 (username \"me\"))"
  (let ((field
	 (let ((deactivate-mark deactivate-mark))
	   (save-excursion
	     (save-restriction
	       (message-narrow-to-headers)
	       (mail-fetch-field "X-My-MSA-Configuration" nil nil t))))))
    (let ((n (length field)))
      (cond
       ((equal n 0) nil)
       ((equal n 1) (read (car field)))
       (t
	(error
	 "In the message header field \"X-My-MSA-Configuration\",
there must be specified at most one list of message submission
configuration keyword assignments, not %S"
	 n))
	))))

(defun my-utils-copy-symbol-values
  (thevars From To)
  "For all THEVARS, copy a symbol-value from obarray FROM to obarray TO.
For each symbol in the obarray THEVARS, do the following:
  If there is a variable with the same name in FROM, intern a symbol with
  the same name into the obarray TO and assign it the symbol-value of the
  symbol in obarray FROM.
  If there is no variable with the same name in FROM, then, if there is a
  symbol with the same name in TO, make its symbol-value unbound.
The obarray TO is returned as the function's value."
  (mapatoms
   (cond
    ((eq thevars From)
     ;; Copy all variables in From, i.e. in the function in the
     ;; default case, below, there is (eq thevars From) and
     ;; (eq sourcesymbol symbol).
     (function
      (lambda (sourcesymbol)
	(let
	    ((symbolname (symbol-name sourcesymbol)))
	  (if (boundp sourcesymbol)
	      ;; Copy its value into a variable in the obarray To:
	      (set (intern symbolname To)
		   (symbol-value sourcesymbol))
	    ;; Else: If a destinationsymbol exists, make its value unbound:
	    (let ((destinationsymbol
		   (intern-soft symbolname To)))
	      (if destinationsymbol
		  (makunbound destinationsymbol))))))))
    ((eq thevars To)
     ;; Assign to all variables in To a value of the corresponding
     ;; symbol in From.  If the symbol in From does not exist
     ;; or has got no symbol-value, make the symbol in To unbound.
     (function
      (lambda (destinationsymbol)
	(let*
	    ((symbolname (symbol-name destinationsymbol))
	     (sourcesymbol
	      (intern-soft symbolname From)))
	  (if (and sourcesymbol (boundp sourcesymbol))
	      ;; sourcesymbol is a variable with the name of
	      ;; destinationsymbol. Copy its value into the variable in
	      ;; the obarray To:
	      (set destinationsymbol (symbol-value sourcesymbol))
	    ;; Else let the value of the corresponding variable in the
	    ;; obarray To be unbound.
	    (makunbound destinationsymbol))))))
    (t
     (function
      (lambda (symbol)
	(let*
	    ((symbolname (symbol-name symbol))
	     (sourcesymbol
	      (intern-soft symbolname From)))
	  (if (and sourcesymbol (boundp sourcesymbol))
	      ;; sourcesymbol is a variable with the name of
	      ;; symbol. Copy its value into a variable in the obarray
	      ;; To:
	      (set (intern symbolname To)
		   (symbol-value sourcesymbol))
	    ;; Else: If a destinationsymbol exists, make its value unbound:
	    (let ((destinationsymbol
		   (intern-soft symbolname To)))
	      (if destinationsymbol
		  (makunbound destinationsymbol)))))))))
   thevars))

(defun my-car-strict (cons)
  "signals error, iff cons is not a cons cell, else returns '(car cons)'."
  (if (consp cons)
      (car cons)
    (signal 'wrong-type-argument (list 'consp cons))))

(defun my-cdr-strict (cons)
  "signals error, iff cons is not a cons cell, else returns '(cdr cons)'."
  (if (consp cons)
      (cdr cons)
    (signal 'wrong-type-argument (list 'consp cons))))



^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, back to index

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-06  9:57 How to change from address while in message buffer? Pankaj Jangid
2020-01-06 21:42 ` dick.r.chiang
2020-01-06 22:33   ` Eric Abrahamsen
2020-01-06 23:39     ` dick.r.chiang
2020-01-07  4:12       ` Eric Abrahamsen
2020-01-07  6:29         ` Pankaj Jangid
2020-01-07 17:32           ` If you read this instead of my name it worked for me
2020-01-07 17:43           ` Eric Abrahamsen
2020-01-07  6:28   ` Vincent Bernat
2020-01-09  1:55     ` 황병희
2020-01-10  5:59       ` Bob Newell
2020-01-18  1:59         ` 황병희
2020-01-07  7:58   ` Vegard Vesterheim
2020-01-07 10:44     ` Pankaj Jangid
2020-01-07 11:41       ` Vegard Vesterheim
2020-01-07 16:19         ` Pankaj Jangid
2020-01-06 22:08 ` Malcolm Purvis
2020-01-07  6:38   ` Pankaj Jangid
2020-02-07 13:42     ` Helmut Waitzmann
2020-02-07 22:09     ` Helmut Waitzmann

Gnus development mailing list

Archives are clonable: git clone --mirror http://inbox.vuxu.org/ding

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://inbox.vuxu.org/vuxu.archive.emacs.gnus.general


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git