Repository: ansible-collections/community.general

Issue:
`mail` callback plugin doesn’t support non-ASCII characters in sender and recipient name
### Summary

The non-ASCII characters in the sender or recipient names are not properly encoded in the emails sent by the `mail` callback plugin.

### Issue Type

Bug Report

### Component Name

`community.general.mail` callback plugin

### Ansible Version

```console (paste below)
$ ansible --version
ansible [core 2.12.1]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/lenaic/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.10/site-packages/ansible
  ansible collection location = /home/lenaic/.ansible/collections:/usr/share/ansible/collections
  executable location = /bin/ansible
  python version = 3.10.1 (main, Dec 18 2021, 23:53:45) [GCC 11.1.0]
  jinja version = 3.0.3
  libyaml = True
```

### Community.general Version

```console (paste below)
$ ansible-galaxy collection list community.general

# /usr/lib/python3.10/site-packages/ansible_collections
Collection        Version
----------------- -------
community.general 4.3.0  
```


### Configuration

```console (paste below)
$ ansible-config dump --only-changed
CACHE_PLUGIN(/home/lenaic/doc/devel/perso/lenaic_config/ansible-libvirt.cfg) = jsonfile
CACHE_PLUGIN_CONNECTION(/home/lenaic/doc/devel/perso/lenaic_config/ansible-libvirt.cfg) = ~/.ansible/tmp/facts_cache
CACHE_PLUGIN_TIMEOUT(/home/lenaic/doc/devel/perso/lenaic_config/ansible-libvirt.cfg) = 86400
CALLBACKS_ENABLED(/home/lenaic/doc/devel/perso/lenaic_config/ansible-libvirt.cfg) = ['community.general.mail']
DEFAULT_FORCE_HANDLERS(/home/lenaic/doc/devel/perso/lenaic_config/ansible-libvirt.cfg) = True
DEFAULT_GATHERING(/home/lenaic/doc/devel/perso/lenaic_config/ansible-libvirt.cfg) = smart
DEFAULT_HOST_LIST(/home/lenaic/doc/devel/perso/lenaic_config/ansible-libvirt.cfg) = ['/home/lenaic/doc/devel/perso/lenaic_config/inventory-libvirt.yaml']
DEFAULT_VAULT_PASSWORD_FILE(/home/lenaic/doc/devel/perso/lenaic_config/ansible-libvirt.cfg) = /home/lenaic/doc/devel/perso/lenaic_config/.vault_password
INVENTORY_ENABLED(/home/lenaic/doc/devel/perso/lenaic_config/ansible-libvirt.cfg) = ['community.libvirt.libvirt']
RETRY_FILES_ENABLED(/home/lenaic/doc/devel/perso/lenaic_config/ansible-libvirt.cfg) = False
```

### OS / Environment

```console
$ cat /etc/os-release 
NAME="Arch Linux"
PRETTY_NAME="Arch Linux"
ID=arch
BUILD_ID=rolling
ANSI_COLOR="38;2;23;147;209"
HOME_URL="https://archlinux.org/"
DOCUMENTATION_URL="https://wiki.archlinux.org/"
SUPPORT_URL="https://bbs.archlinux.org/"
BUG_REPORT_URL="https://bugs.archlinux.org/"
LOGO=archlinux-logo
```

### Steps to Reproduce

Enable the `community.general.mail` callback plugin thanks to the following configuration options

```ini
[defaults]
callbacks_enabled = community.general.mail

[callback_mail]
to = Lénaïc <me@my.mail.provider>
sender = Ansible <noreply@my.mail.provider>
```

And try to launch a playbook some tasks of which are failing.

### Expected Results

I receive a mail the sender of which is `Lénaïc <me@my.mail.provider>`.

### Actual Results

I receive a mail the sender of which is `LÃ©naÃ¯c <me@my.mail.provider>`.

### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:
Files identified in the description:
* `lib/ansible/plugins/callback`

If these files are incorrect, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/devel/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->

Resolving patch:
diff --git a/plugins/callback/mail.py b/plugins/callback/mail.py
--- a/plugins/callback/mail.py
+++ b/plugins/callback/mail.py
@@ -120,27 +120,34 @@ def mail(self, subject='Ansible error mail', body=None):
 
         smtp = smtplib.SMTP(self.smtphost, port=self.smtpport)
 
+        sender_address = email.utils.parseaddr(self.sender)
+        if self.to:
+            to_addresses = email.utils.getaddresses(self.to)
+        if self.cc:
+            cc_addresses = email.utils.getaddresses(self.cc)
+        if self.bcc:
+            bcc_addresses = email.utils.getaddresses(self.bcc)
+
         content = 'Date: %s\n' % email.utils.formatdate()
-        content += 'From: %s\n' % self.sender
+        content += 'From: %s\n' % email.utils.formataddr(sender_address)
         if self.to:
-            content += 'To: %s\n' % ','.join(self.to)
+            content += 'To: %s\n' % ', '.join([email.utils.formataddr(pair) for pair in to_addresses])
         if self.cc:
-            content += 'Cc: %s\n' % ','.join(self.cc)
+            content += 'Cc: %s\n' % ', '.join([email.utils.formataddr(pair) for pair in cc_addresses])
         content += 'Message-ID: %s\n' % email.utils.make_msgid()
         content += 'Subject: %s\n\n' % subject.strip()
         content += body
 
-        addresses = self.to
+        addresses = to_addresses
         if self.cc:
-            addresses += self.cc
+            addresses += cc_addresses
         if self.bcc:
-            addresses += self.bcc
+            addresses += bcc_addresses
 
         if not addresses:
             self._display.warning('No receiver has been specified for the mail callback plugin.')
 
-        for address in addresses:
-            smtp.sendmail(self.sender, address, to_bytes(content))
+        smtp.sendmail(self.sender, [address for name, address in addresses], to_bytes(content))
 
         smtp.quit()
 


Test patch: