diff --git a/VERSIONS_HOTLINE/90745 b/VERSIONS_HOTLINE/90745
new file mode 100644
index 0000000000000000000000000000000000000000..cc61df1bb86ec2a93eea1832fd2bff1efef4795e
--- /dev/null
+++ b/VERSIONS_HOTLINE/90745
@@ -0,0 +1 @@
+ - ticket #90745 : les mails sont toujours encodés en UTF8. Possibilité de personnaliser le sujet des mails de notification d'un enregistrement utilisateur.
\ No newline at end of file
diff --git a/application/modules/opac/controllers/AuthController.php b/application/modules/opac/controllers/AuthController.php
index a8c1cc030263c83714fd7ea075ae857392eb7675..90cd4f88b41b5b398514cc514a4807f36d5cc08f 100644
--- a/application/modules/opac/controllers/AuthController.php
+++ b/application/modules/opac/controllers/AuthController.php
@@ -402,9 +402,8 @@ class AuthController extends ZendAfi_Controller_Action {
 
     $data = ZendAfi_Filters_Post::filterStatic($this->_request->getPost());
 
-    $class_user = new Class_Users();
     $data['cle'] = md5($data['mail']);
-    $ret = $class_user->registerUser($data);
+    $ret = (new Class_User_Registration())->registerUser($data);
 
     // Affichage des erreurs
     if(isset($ret["error"])) {
diff --git a/cosmogramme/sql/patch/patch_375.php b/cosmogramme/sql/patch/patch_375.php
new file mode 100644
index 0000000000000000000000000000000000000000..8e4a9e4cf8e180752b6091d2464a40a57d5e17ed
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_375.php
@@ -0,0 +1,6 @@
+<?php
+$adapter = Zend_Db_Table_Abstract::getDefaultAdapter();
+try {
+  $adapter->query('UPDATE bib_admin_var set valeur=replace(valeur, \'\\\\n\', \'<br>\') where clef in("NOTIFICATION_TEMPLATE_NEW_REGISTRATION", "NOTIFICATION_TEMPLATE_NEW_USER")');
+
+} catch(Exception $e) {}
diff --git a/library/Class/AdminVar.php b/library/Class/AdminVar.php
index bc0fbfd3388d8ae635d0d58d967e5c4651828037..76f61f05955a6de96a2f6ab405f037ecb3658c3c 100644
--- a/library/Class/AdminVar.php
+++ b/library/Class/AdminVar.php
@@ -124,6 +124,7 @@ class Class_AdminVarLoader extends Storm_Model_Loader {
        'modo' => $this->_getModerationVars(),
        'stat' => $this->_getStatVars(),
        'global' => $this->_getGlobalVars(),
+       'registration' => $this->_getRegistrationVars(),
        'cosmogramme' => $this->_getCosmogrammeVars(),
        'catalogue' => $this->_getCatalogVars(),
        'newsletter' => $this->_getNewsletterVars(),
@@ -150,6 +151,20 @@ class Class_AdminVarLoader extends Storm_Model_Loader {
   }
 
 
+
+  protected function _getRegistrationVars() {
+    return [
+            'NOTIFICATION_TEMPLATE_NEW_USER' => Class_AdminVar_Meta::newEditor($this->_('Modèle utilisé pour les courriels de notification des nouveaux utilisateurs.'),
+                                                                                      ['value'=> 'Bonjour,<br><br>{user.lastname} {user.firstname} a fait une demande d\'inscription pour la bibliothèque {bib.libelle} avec la carte {user.idabon}.<br><br>Vous pouvez cliquer sur le lien suivant pour visualiser la demande d\'enregistrement : {profil.absolute_url}/admin/registration/ .<br><br>Bien à vous.']),
+
+            'NOTIFICATION_TEMPLATE_NEW_REGISTRATION' => Class_AdminVar_Meta::newEditor($this->_('Modèle utilisé pour les courriels d\'accueil des nouveaux utilisateurs.'),
+                                                                                       ['value'=> 'Bonjour,<br><br>Vous avez fait une demande d\'inscription sur le portail {profil.libelle} de la bibliothèque {profil.bib_libelle}.<br><br>Pour activer votre compte, merci de cliquer sur le lien suivant {profil.absolute_url}/opac/auth/activeuser?c={user.cle} .<br><br>Si vous n\'êtes pas à l\'origine de cette demande d\'inscription, merci de ne pas tenir compte de cet e-mail, et l\'inscription ne sera pas activée.']),
+
+            'NOTIFICATION_TEMPLATE_NEW_REGISTRATION_SUBJECT' => Class_AdminVar_Meta::newDefault($this->_('Sujet des courriels d\'accueil des nouveaux utilisateurs.'),
+                                                                                                ['value'=> 'Demande d\'inscription: {profil.libelle}'])];
+  }
+
+
   protected function _getStaticAlbumVars() {
     return ['ALBUMS_LIST_MODE' => Class_AdminVar_Meta::newOnOff($this->_('Le gestionnaire de contenu affiche les albums sous forme de liste paginée au lieu de d\'une arborescence. Cet affichage est adapté lorsque le nombre d\'albums devient trop important')),
 
@@ -381,10 +396,6 @@ class Class_AdminVarLoader extends Storm_Model_Loader {
                                                           ['value' => 0])->bePrivate(),
             'NOTIFICATION_TEMPLATE_NEW_RESERVATION' => Class_AdminVar_Meta::newEditor($this->_('Modèle utilisé pour les courriels de notification des réservations.'),
                                                                                       ['value'=> '<p>Bonjour,</p> <p>L\'usager {user.nom_complet} {user.idabon} a fait une demande de réservation sur l\'exemplaire :</p><p><ul><li>Code Barre : {item.code_barres}</li><li>Titre : {item.titre_et_sous_titre}</li><li>Type de Document : {notice.type_doc_label}</li><li>Annexe de retrait : {annexe_code.libelle} </li></ul></p>']),
-            'NOTIFICATION_TEMPLATE_NEW_USER' => Class_AdminVar_Meta::newEditor($this->_('Modèle utilisé pour les courriels de notification des nouveaux utiliateurs.'),
-                                                                                      ['value'=> 'Bonjour,\n\n{user.lastname} {user.firstname} a fait une demande d\'inscription pour la bibliothèque {bib.libelle} avec la carte {user.idabon}.\n\nVous pouvez cliquer sur le lien suivant pour visualiser la demande d\'enregistrement : {profil.absolute_url}/admin/registration/ .\n\nBien à vous.']),
-            'NOTIFICATION_TEMPLATE_NEW_REGISTRATION' => Class_AdminVar_Meta::newEditor($this->_('Modèle utilisé pour les courriels d\'accueil des nouveaux utilisateurs.'),
-                                                                                       ['value'=> 'Bonjour,\n\nVous avez fait une demande d\'inscription sur le portail {profil.libelle} de la bibliothèque {profil.bib_libelle}.\n\nPour activer votre compte, merci de cliquer sur le lien suivant {profil.absolute_url}/opac/auth/activeuser?c={user.cle} .\n\nSi vous n\'êtes pas à l\'origine de cette demande d\'inscription, merci de ne pas tenir compte de cet e-mail, et l\'inscription ne sera pas activée.']),
             'GENERATION_SITE' => Class_AdminVar_Meta::newOnOff($this->_('Activation de la génération de site.')),
             'CUSTOM_FIELDS_REPORT' => Class_AdminVar_Meta::newOnOff($this->_('Activation des rapports statistiques sur les champs personnalisés')),
             'WEBSERVICE_TEST' => Class_AdminVar_Meta::newOnOff($this->_('Activation des tests de webservices')),
diff --git a/library/Class/User/Registration.php b/library/Class/User/Registration.php
new file mode 100644
index 0000000000000000000000000000000000000000..11dbeedda20d2bf38993be412d95e3198a9f186e
--- /dev/null
+++ b/library/Class/User/Registration.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * Copyright (c) 2012-2019, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class Class_User_Registration {
+  use
+    Trait_Translator,
+    Trait_TimeSource;
+
+  public function registerUser($data) {
+    if (Class_Users::isLoginExists($data['login']))
+      return ['error' => $this->_("Cet identifiant existe déjà.")];
+
+    $attribs = array_intersect_key($data,
+                                   ['login' => '',
+                                    'password' => '',
+                                    'mail' => '',
+                                    'cle' => '',
+                                    'id_site' => 0,
+                                    'idabon' => '',
+                                    'lastname' => '',
+                                    'firstname' => '']);
+
+    $attribs['password'] = $data['mdp'];
+    $attribs['date'] = static::getCurrentDateTime();
+
+    $new_user = Class_UsersNonValid::newInstance($attribs);
+    $new_user->save();
+
+    $attribs['user'] = $new_user;
+
+    $attribs['profil'] = $profil = Class_Profil::getCurrentProfil();
+    $attribs['bib']    = $profil->getBib();
+
+    // envoi du mail de confirmation
+    $attribs['mail_admin'] = $profil->getMailSiteOrPortail();
+
+    if(isset($attribs['id_site']) &&
+       ($bib = Class_Bib::find($attribs['id_site'])) &&
+       $bib->getNotifyOnNewUser())
+
+      {
+
+        $attribs['bib'] = $bib;
+        $ret = $this->_sendMessage($attribs,'Bib');
+      }
+
+    $ret = $this->_sendMessage($attribs,'User');
+
+    if(isset($ret["error"])) return $ret;
+
+    $message_confirm = $profil->getCfgModulesPreferences('auth', 'register')['register_confirm'];
+    $ret["message_confirm"]=nl2br($message_confirm);
+
+    return $ret;
+  }
+
+
+  protected function _sendMessage($attribs, $recipient){
+    try {
+      (new ZendAfi_Mail('utf8'))
+        ->setSubject($this->_generateMessageSubject($attribs))
+        ->setBodyHtml($this->_generateMessageBody($attribs, $recipient))
+        ->setFrom($attribs['mail_admin'])
+        ->addTo($recipient == 'User' ? $attribs['mail']:$attribs['bib']->getMail())
+        ->addBcc($attribs['mail_admin'])
+        ->send();
+    } catch (Exception $e) {
+      $ret["error"] = $e->getMessage();
+      return $ret;
+    }
+  }
+
+
+  protected function _generateMessageBody($attribs, $recipient = 'Bib'){
+    $template_name_extension = 'USER';
+    if ($recipient == 'User'){
+      $template_name_extension = "REGISTRATION";
+    }
+
+    $modelfusion = (new Class_ModeleFusion())
+      ->setContenu(Class_AdminVar::getValueOrDefault('NOTIFICATION_TEMPLATE_NEW_'.$template_name_extension));
+
+    $body = $modelfusion->setDataSource(['profil'=> $attribs['profil'],
+                                         'bib' =>   $attribs['bib'],
+                                         'user' =>  $attribs['user']])
+                        ->getContenuFusionne();
+    return $body;
+  }
+
+
+  protected function _generateMessageSubject($attribs) {
+    return  (new Class_ModeleFusion())
+      ->setContenu(Class_AdminVar::getValueOrDefault('NOTIFICATION_TEMPLATE_NEW_REGISTRATION_SUBJECT'))
+      ->setDataSource(['profil'=> $attribs['profil'],
+                       'bib' =>   $attribs['bib'],
+                       'user' =>  $attribs['user']])
+      ->getContenuFusionne();
+  }
+}
diff --git a/library/Class/Users.php b/library/Class/Users.php
index fcbb325b3fb56979a4c616077acab8dbbe98466a..265e6187f01f899f94742c0528b2f14aac099f60 100644
--- a/library/Class/Users.php
+++ b/library/Class/Users.php
@@ -30,6 +30,15 @@ class UsersLoader extends Storm_Model_Loader {
   }
 
 
+  public function isLoginExists($login) {
+    $login = (trim($login));
+
+    $login = Class_Users::findFirstBy(['login' => $login]);
+    return $login ? true : false;
+  }
+
+
+
   protected function findUsersById($ids) {
     if(!is_array($ids)
        || 0 == count(array_filter($ids)))
@@ -1039,17 +1048,9 @@ class Class_Users extends Storm_Model_Abstract {
   }
 
 
-  public function ifLoginExist($login) {
-    $login = (trim($login));
-
-    $login = $this->getLoader()->findFirstBy(array('login' => $login));
-    return $login ? true : false;
-  }
-
-
   protected function _isUnique() {
     if (!$this->getIdSigb())
-      return (!$this->ifLoginExist($this->getLogin()));
+      return (!$this->getLoader()->isLoginExists($this->getLogin()));
     return 0 == $this->getLoader()->countBy(['id_sigb' => $this->getIdSigb(),
                                              'login' => $this->getLogin()]);
   }
@@ -1113,95 +1114,6 @@ class Class_Users extends Storm_Model_Abstract {
   }
 
 
-  public function registerUser($data) {
-    if ($this->ifLoginExist($data['login']))
-      return ['error' => $this->_("Cet identifiant existe déjà.")];
-
-    $attribs = array_intersect_key($data,
-                                   ['login' => '',
-                                    'password' => '',
-                                    'mail' => '',
-                                    'cle' => '',
-                                    'id_site' => 0,
-                                    'idabon' => '',
-                                    'lastname' => '',
-                                    'firstname' => '']);
-
-    $attribs['password'] = $data['mdp'];
-    $attribs['date'] = static::getCurrentDateTime();
-
-    $new_user = Class_UsersNonValid::newInstance($attribs);
-    $new_user->save();
-
-    $attribs['user'] = $new_user;
-
-    $attribs['profil'] = $profil = Class_Profil::getCurrentProfil();
-    $attribs['bib']    = $profil->getBib();
-
-    // envoi du mail de confirmation
-    $attribs['mail_admin'] = $profil->getMailSiteOrPortail();
-
-    if(isset($attribs['id_site']) &&
-       ($bib = Class_Bib::find($attribs['id_site'])) &&
-       $bib->getNotifyOnNewUser())
-
-      {
-
-        $attribs['bib'] = $bib;
-        $ret = $this->_sendMessage($attribs,'Bib');
-      }
-
-    $ret = $this->_sendMessage($attribs,'User');
-
-    if(isset($ret["error"])) return $ret;
-
-    $message_confirm = $profil->getCfgModulesPreferences('auth', 'register')['register_confirm'];
-    $ret["message_confirm"]=nl2br($message_confirm);
-
-    return $ret;
-  }
-
-
-  protected function _sendMessage($attribs, $recipient){
-
-    try {
-      (new ZendAfi_Mail('utf8'))
-        ->setSubject($attribs['profil']->getLibelle())
-        ->setBodyText($this->_generateMessageBody($attribs, $recipient))
-        ->setFrom($attribs['mail_admin'])
-        ->addTo($recipient == 'User' ? $attribs['mail']:$attribs['bib']->getMail())
-        ->addBcc($attribs['mail_admin'])
-        ->send();
-    } catch (Exception $e) {
-      $ret["error"] = $e->getMessage();
-      return $ret;
-    }
-  }
-
-  protected function _generateMessageBody($attribs, $recipient = 'Bib'){
-    $template_name_extension = 'USER';
-    if ($recipient == 'User'){
-      $template_name_extension = "REGISTRATION";
-    }
-
-    $modelfusion = (new Class_ModeleFusion())
-      ->setContenu(Class_AdminVar::getValueOrDefault('NOTIFICATION_TEMPLATE_NEW_'.$template_name_extension));
-
-    $body = $modelfusion->setDataSource(['profil'=> $attribs['profil'],
-                                         'bib' =>   $attribs['bib'],
-                                         'user' =>  $attribs['user']])
-                        ->getContenuFusionne();
-    return $body;
-  }
-
-
-
-  public function getUsersNonValid()
-  {
-    $users = fetchAll("Select * from bib_admin_users_non_valid order by DATE DESC");
-    return($users);
-  }
-
 
   public function getNomAff($id_user = null, $complet = false) {
     if ($id_user != null) {
diff --git a/library/ZendAfi/Mail.php b/library/ZendAfi/Mail.php
index a1b7039c084f39212dc7b2f0814ee0b2369f80ff..76f1f22b0890426cf6e78e070e2daa101d4575fa 100644
--- a/library/ZendAfi/Mail.php
+++ b/library/ZendAfi/Mail.php
@@ -67,33 +67,6 @@ class ZendAfi_Mail extends Zend_Mail {
   }
 
 
-  /**
-   * @param   string    $subject
-   * @return  Zend_Mail Provides fluent interface
-   * @throws  Zend_Mail_Exception
-   */
-  public function setSubject($subject) {
-    if ($this->_subject === null) {
-      $subject = strtr($subject, "\r\n\t", '???');
-      $this->_subject = $subject;
-      $this->_storeHeader('Subject', $this->_subject);
-      return $this;
-    }
-
-    /**
-     * @see Zend_Mail_Exception
-     */
-    require_once 'Zend/Mail/Exception.php';
-    throw new Zend_Mail_Exception('Subject set twice');
-  }
-
-
-  public function setBodyText($txt, $charset = null, $encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE) {
-    parent::setBodyText($txt, 'utf-8', Zend_Mime::ENCODING_8BIT);
-    return $this;
-  }
-
-
   public function clearRecipients() {
     $this->_recipients = [];
     $this->_headers['To'] = [];
diff --git a/tests/application/modules/admin/controllers/CmsControllerTest.php b/tests/application/modules/admin/controllers/CmsControllerTest.php
index 88e4ac615ee8706dec4d0d94ec5f56c092fc9a24..02462f8436103a3bf2ef76f707b19c6d0b8f0ac3 100644
--- a/tests/application/modules/admin/controllers/CmsControllerTest.php
+++ b/tests/application/modules/admin/controllers/CmsControllerTest.php
@@ -1711,7 +1711,8 @@ class CmsControllerNewsAddActionPostWithWorkflowTest
   /** @test */
   public function sentMailToAuthorWhenNewsIsValidatedShouldContainsDefaultSubject() {
     $this->postArticleValidated();
-    $this->assertEquals('[Bokeh] Validation de l\'article Katsuhiro Otomo en dédicace !',quoted_printable_decode($this->mock_transport->getSentMails()[0]->getSubject()));
+    $this->assertEquals('=?utf8?Q?[Bokeh] Validation de l\'article Katsuhiro Otomo en dédicace !?',
+                        quoted_printable_decode($this->mock_transport->getSentMails()[0]->getSubject()));
   }
 
 
@@ -1808,7 +1809,8 @@ class CmsControllerNewsAddActionPostWithWorkflowTest
   /** @test */
   public function sentMailToAdminWhenValidationPendingShouldContainsDefaultTitle() {
     $this->postArticleAValider();
-    $this->assertEquals('[Bokeh] Validation d\'article en attente: Katsuhiro Otomo en dédicace !',quoted_printable_decode($this->mock_transport->getSentMails()[0]->getSubject()));
+    $this->assertContains('[Bokeh] Validation d\'article en attente: Katsuhiro Otomo en dédicace !',
+                          quoted_printable_decode($this->mock_transport->getSentMails()[0]->getSubject()));
   }
 
 
@@ -1976,7 +1978,8 @@ class CmsControllerWorkflowArticleRefusedTest extends CmsControllerWorkflowTestC
   /** @test */
   public function sentMailToUserWhenRefusedShouldContainsDefaultTitle() {
     $this->postArticleRefuser();
-    $this->assertEquals('[Bokeh] Refus de l\'article Katsuhiro Otomo en dédicace !',quoted_printable_decode($this->mock_transport->getSentMails()[0]->getSubject()));
+    $this->assertContains('[Bokeh] Refus de l\'article Katsuhiro Otomo en dédicace !',
+                          quoted_printable_decode($this->mock_transport->getSentMails()[0]->getSubject()));
   }
 
 
diff --git a/tests/application/modules/admin/controllers/ModoControllerFormulaireTest.php b/tests/application/modules/admin/controllers/ModoControllerFormulaireTest.php
index 1265516790cbd31d6aba5f035887772d376ce6da..f79176639209d053c7213adec4d0b7d26bbec410 100644
--- a/tests/application/modules/admin/controllers/ModoControllerFormulaireTest.php
+++ b/tests/application/modules/admin/controllers/ModoControllerFormulaireTest.php
@@ -554,9 +554,11 @@ class ModoControllerFormulaireVisualiserReponseArticleSendResponseByMailTest ext
   }
 
 
-/** @test **/
+  /** @test **/
   public function mailBodyShouldBeLesLits() {
-    $this->assertEquals("Les lits sont trop petits pour aujourd'hui! éèà@€ôö",$this->mock_transport->getSentMails()[0]->getBodyText()->getContent());
+    $this->assertEquals("Les lits sont trop petits pour aujourd'hui! =C3=A9=C3=A8=C3=A0@=E2=82=AC=
+=C3=B4=C3=B6",
+                        $this->mock_transport->getSentMails()[0]->getBodyText()->getContent());
   }
 
 
diff --git a/tests/application/modules/opac/controllers/AbonneControllerActivitiesTest.php b/tests/application/modules/opac/controllers/AbonneControllerActivitiesTest.php
index 752d13fd0eaaaf33fd2a8b0b4be31f93a0edc0dc..bb93289eeed201ce2b5006b8632ea0e0ed19c8d8 100644
--- a/tests/application/modules/opac/controllers/AbonneControllerActivitiesTest.php
+++ b/tests/application/modules/opac/controllers/AbonneControllerActivitiesTest.php
@@ -706,8 +706,8 @@ class AbonneControllerActivitiesAmadouInscritSessionFebruaryJavaOpenTest extends
 
   /** @test */
   public function firstMailSubjectShouldBeRegistrationConfirmation() {
-    $this->assertEquals('Confirmation d\'inscription à l\'activité "Learn Java"',
-                        $this->_mails[0]->getSubject());
+    $this->assertEquals('=?utf8?Q?Confirmation d\'inscription à l\'activité "Learn Java"?',
+                        quoted_printable_decode($this->_mails[0]->getSubject()));
   }
 
 
@@ -740,8 +740,8 @@ class AbonneControllerActivitiesAmadouInscritSessionFebruaryJavaOpenTest extends
 
   /** @test */
   public function secondMailSubjectShouldBeNewRegistration() {
-    $this->assertEquals('Nouvelle inscription à l\'activité "Learn Java"',
-                        $this->_mails[1]->getSubject());
+    $this->assertContains('Nouvelle inscription à l\'activité "Learn Java"',
+                          quoted_printable_decode($this->_mails[1]->getSubject()));
   }
 
 
@@ -943,8 +943,8 @@ class AbonneControllerActivitiesAmadouDesinscritSessionJuilletPythonTest
 
   /** @test */
   public function firstMailSubjectShouldContainsUnregistrationConfirmation() {
-    $this->assertEquals('Confirmation de désinscription à l\'activité "Learn Python"',
-                        $this->_mails[0]->getSubject());
+    $this->assertContains('Confirmation de désinscription à l\'activité "Learn Python"',
+                          quoted_printable_decode($this->_mails[0]->getSubject()));
   }
 
 
@@ -958,8 +958,8 @@ class AbonneControllerActivitiesAmadouDesinscritSessionJuilletPythonTest
 
   /** @test */
   public function secondMailSubjectShouldBeUnregistration() {
-    $this->assertEquals('Désinscription de l\'activité "Learn Python"',
-                        $this->_mails[1]->getSubject());
+    $this->assertContains('Désinscription de l\'activité "Learn Python"',
+                          quoted_printable_decode($this->_mails[1]->getSubject()));
   }
 
 
diff --git a/tests/application/modules/opac/controllers/AuthControllerPreRegistrationTest.php b/tests/application/modules/opac/controllers/AuthControllerPreRegistrationTest.php
index ea485a996dcae6a40f3237c2a6dcd40fbe095cfb..6e1f538461fa7a0f1d51e8f37eee1ca75427d7c2 100644
--- a/tests/application/modules/opac/controllers/AuthControllerPreRegistrationTest.php
+++ b/tests/application/modules/opac/controllers/AuthControllerPreRegistrationTest.php
@@ -169,7 +169,8 @@ class AuthControllerPreRegistrationKohaPostDispatchTest extends AuthControllerPr
 
   /** @test */
   public function mailSubjectShouldBePréinscriptionÀLaMédiathèqueDeGrans() {
-    $this->assertEquals('Préinscription à Médiathèque de Grans', $this->mock_transport->getSentMails()[0]->getSubject());
+    $this->assertContains('Préinscription à Médiathèque de Grans',
+                          quoted_printable_decode($this->mock_transport->getSentMails()[0]->getSubject()));
   }
 }
 
@@ -402,7 +403,8 @@ class AuthControllerPreRegistrationNanookPostDispatchTest
 
   /** @test */
   public function mailSubjectShouldBePréinscriptionÀArcadia() {
-    $this->assertEquals('Préinscription à Arcadia', $this->mock_transport->getSentMails()[0]->getSubject());
+    $this->assertContains('Préinscription à Arcadia',
+                          quoted_printable_decode($this->mock_transport->getSentMails()[0]->getSubject()));
   }
 }
 
diff --git a/tests/application/modules/opac/controllers/AuthControllerTest.php b/tests/application/modules/opac/controllers/AuthControllerTest.php
index 04425b9451f3dda5b25403946262a06ba8f77a92..3825c8649501ef48b40b7da3e7851526fbd002c1 100644
--- a/tests/application/modules/opac/controllers/AuthControllerTest.php
+++ b/tests/application/modules/opac/controllers/AuthControllerTest.php
@@ -1554,9 +1554,14 @@ class AuthControllerNobodyLoggedRegisterPostRightDatasTest
   public function setUp() {
     parent::setUp();
     $time_source = new TimeSourceForTest('2018-17-001 14:14:14');
-    Class_Users::setTimeSource($time_source);
+    Class_User_Registration::setTimeSource($time_source);
     $_SERVER['HTTPS'] = 'On';
 
+
+    Class_Profil::getCurrentProfil()
+      ->setLibelle('Nôtre cœeur')
+      ->save();
+
     $this->postDispatch('auth/register',
                         ['login' => 'mario',
                          'mail' => 'mario@afi-sa.fr',
@@ -1569,7 +1574,7 @@ class AuthControllerNobodyLoggedRegisterPostRightDatasTest
 
     $this->_from = $this->getSentMail()->getFrom();
     $this->_recipients = $this->getSentMail()->getRecipients();
-    $this->_content = $this->getSentMail()->getBodyText(true);
+    $this->_content = quoted_printable_decode($this->getSentMail()->getBodyHtml(true));
   }
 
 
@@ -1579,6 +1584,13 @@ class AuthControllerNobodyLoggedRegisterPostRightDatasTest
   }
 
 
+  /** @test */
+  public function subjectShouldBeNôtreCœurWithUTF8Charset() {
+    $this->assertEquals('=?utf8?Q?Demande=20d\'inscription:=20N=C3=B4tre=20c=C5=93eur?=',
+                        $this->getSentMail()->getHeaders()['Subject'][0]);
+  }
+
+
   /** @test */
   public function recipientShouldBeMario() {
     $this->assertContains('mario@afi-sa.fr', $this->_recipients);
@@ -1605,6 +1617,12 @@ class AuthControllerNobodyLoggedRegisterPostRightDatasTest
   }
 
 
+  /** @test */
+  public function contentShouldContainsNôtreCœeur() {
+    $this->assertContains('Nôtre cœeur', $this->_content);
+  }
+
+
   /** @test */
   public function confirmationShouldContainsCoucouAndThanks() {
     $this->assertXPathContentContains('//div',
@@ -1631,7 +1649,7 @@ class AuthControllerNobodyLoggedRegisterPostRightDatasTest
                          'idabon' => '',
                          'lastname' => 'bros',
                          'firstname' => 'mario',
-                         'date' => Class_Users::getCurrentDateTime(),
+                         'date' => Class_User_Registration::getCurrentDateTime(),
                          'bib_user_id' => null],
                         $user->getRawAttributes());
   }
@@ -1645,7 +1663,7 @@ class AuthControllerNobodyLoggedRegisterSendBibNotification extends AuthControll
   public function setUp() {
     parent::setUp();
     $time_source = new TimeSourceForTest('2018-17-001 14:14:14');
-    Class_Users::setTimeSource($time_source);
+    Class_User_Registration::setTimeSource($time_source);
     $_SERVER['HTTPS'] = 'On';
 
     $int_bib = $this->fixture('Class_IntBib',
@@ -1686,27 +1704,30 @@ class AuthControllerNobodyLoggedRegisterSendBibNotification extends AuthControll
     parent::tearDown();
   }
 
+
   /** @test */
   public function newUserShouldTriggerTwoEmails() {
     $this->assertEquals(2, $this->mock_transport->count());
   }
 
+
   /** @test */
   public function firstMessageSentToShouldBeadminpukakaAtExampleDotCom() {
     $this->assertEquals('adminpukapuka@example.com',$this->_sent_mails[0]->getRecipients()[0]);
   }
 
+
   /** @test */
   public function firstMessageSentShouldContainsAdminValidationLink() {
     $this->assertContains('/admin/registration/',
-                          $this->_sent_mails[0]->getBodyText(true));
+                          $this->_sent_mails[0]->getBodyHtml(true));
   }
 
 
   /** @test */
   public function firstMessageShouldContainsBrosMario() {
     $this->assertContains('bros mario',
-                          $this->_sent_mails[0]->getBodyText(true));
+                          $this->_sent_mails[0]->getBodyHtml(true));
   }
 
 
diff --git a/tests/application/modules/opac/controllers/RechercheControllerReservationTest.php b/tests/application/modules/opac/controllers/RechercheControllerReservationTest.php
index c75eca1a4250aeaa82d16396b4c75985096f0fe8..35d11009686023ab40ec69e30a74cddd6a6f4104 100644
--- a/tests/application/modules/opac/controllers/RechercheControllerReservationTest.php
+++ b/tests/application/modules/opac/controllers/RechercheControllerReservationTest.php
@@ -347,7 +347,7 @@ class RechercheControllerReservationWithMailPostAction
 
     $this->_sent_mails = $mock_transport->getSentMails();
     $this->first_mail = array_first($this->_sent_mails);
-    $this->first_content = $this->first_mail->getBodyText()->getContent();
+    $this->first_content = quoted_printable_decode($this->first_mail->getBodyText()->getContent());
     $this->last_mail = array_last($this->_sent_mails);
   }
 
@@ -712,7 +712,8 @@ class RechercheControllerReservationWithMailFormValidPostTest
   /** @test */
   public function mailsShouldHaveHoldQuerySubject() {
     foreach($this->_mails as $mail)
-      $this->assertEquals('Demande de réservation de document', $mail->getSubject());
+      $this->assertContains('Demande de réservation de document',
+                            quoted_printable_decode($mail->getSubject()));
   }
 
 
@@ -990,7 +991,8 @@ class RechercheControllerReservationPickupAjaxAndNotifyByMailEnabledTest
 
   /** @test */
   public function mailSubjectShouldContainsJulianMonsieurSurExemplaire12341() {
-    $this->assertContains("Julian Monsieur sur l'exemplaire 12341",current($this->_sent_mails)->getSubject());
+    $this->assertContains("Julian Monsieur sur l'exemplaire 12341",
+                          quoted_printable_decode(current($this->_sent_mails)->getSubject()));
   }
 
 
diff --git a/tests/db/UpgradeDBTest.php b/tests/db/UpgradeDBTest.php
index b7a41c9dc90d9c7269f5a54bd50d9a3ddce25552..fb412af4b8d982366cd6e97be8cf1a532620cf60 100644
--- a/tests/db/UpgradeDBTest.php
+++ b/tests/db/UpgradeDBTest.php
@@ -2715,4 +2715,28 @@ class UpgradeDB_374_Test extends UpgradeDBTestCase {
   public function tableBibShouldhaveNotifyOnNewUserField() {
     $this->assertColumn('bib_c_site','notify_on_new_user');
   }
+}
+
+
+
+
+class UpgradeDB_375_Test extends UpgradeDBTestCase {
+  public function prepare() {
+    $this->silentQuery('REPLACE INTO bib_admin_var(clef, valeur) VALUES(\'NOTIFICATION_TEMPLATE_NEW_REGISTRATION\', \'Hello\\\\n\\\\nMyFriend\')');
+    $this->silentQuery('REPLACE INTO bib_admin_var(clef, valeur) VALUES(\'NOTIFICATION_TEMPLATE_NEW_USER\', \'Hello\\\\n\\\\nYou have a new friend\')');
+  }
+
+
+  /** @test */
+  public function variableNewRegistrerationShouldContainsBRInsteadOfNL() {
+    $this->assertEquals('Hello<br><br>MyFriend',
+                        $this->query('select valeur from bib_admin_var where clef="NOTIFICATION_TEMPLATE_NEW_REGISTRATION"')->fetch()['valeur']);
+  }
+
+
+  /** @test */
+  public function variableNewUserShouldContainsBRInsteadOfNL() {
+    $this->assertEquals('Hello<br><br>You have a new friend',
+                        $this->query('select valeur from bib_admin_var where clef="NOTIFICATION_TEMPLATE_NEW_USER"')->fetch()['valeur']);
+  }
 }
\ No newline at end of file
diff --git a/tests/library/Class/NewsletterMailingTest.php b/tests/library/Class/NewsletterMailingTest.php
index c93f2730408880fcd79245baffc0e1bafa6acc55..1951286af315aea02e72ca4a59045489fd262655 100644
--- a/tests/library/Class/NewsletterMailingTest.php
+++ b/tests/library/Class/NewsletterMailingTest.php
@@ -215,7 +215,7 @@ class NewsletterMailingAnimationsSendMailTest extends NewsletterMailingTestCase
   public function bodyTextShouldContainsUnsubscribeLinks() {
     $this->assertContains('/newsletter/unsubscribe/newsletter/1/user/2/hash/'
                           . $this->_hashForUser(Class_Users::find(2)),
-                          $this->mails[0]->getBodyText(true));
+                          quoted_printable_decode($this->mails[0]->getBodyText(true)));
 
   }
 
@@ -293,7 +293,7 @@ class NewsletterMailingAnimationsSendWithProfilMailTest extends NewsletterMailin
   public function bodyTextShouldContainsUnsubscribeLinks() {
     $this->assertContains('/newsletter/unsubscribe/newsletter/1/id_profil/45/user/2/hash/'
                           . Class_Newsletter_Template::hashForUser(1,Class_Users::find(2)->getMail()),
-                          $this->mails[0]->getBodyText(true));
+                          quoted_printable_decode($this->mails[0]->getBodyText(true)));
 
   }
 
@@ -326,7 +326,7 @@ class NewsletterMailingAnimationsSendWithUnsubscribeTextMailTest
   /** @test */
   public function bodyTextShouldContainsUnsubscribeText() {
     $this->assertContains('Pour vous désinscrire c\'est par là : ',
-                          $this->mails[1]->getBodyText(true));
+                          quoted_printable_decode($this->mails[1]->getBodyText(true)));
 
   }
 
@@ -585,7 +585,7 @@ class NewsletterMailingRecordAbsoluteUrlTest extends ModelTestCase {
     $mail = Class_Newsletter_Template::newFrom($dispatch)
       ->mailFor(Class_Newsletter_DispatchUser::findFirstBy(['user_id' => 120]));
 
-    $this->_text_content = $mail->getBodyText(true);
+    $this->_text_content = quoted_printable_decode($mail->getBodyText(true));
     $this->_html_content = quoted_printable_decode($mail->getBodyHtml(true));
   }
 
diff --git a/tests/library/Class/SuggestionAchatTest.php b/tests/library/Class/SuggestionAchatTest.php
index 546515c74da70fcb3b95e1aeef269e3d1db1296f..dac9a4bd220ad5f59dc2a93483f6b3d103853ac1 100644
--- a/tests/library/Class/SuggestionAchatTest.php
+++ b/tests/library/Class/SuggestionAchatTest.php
@@ -84,8 +84,8 @@ class SuggestionAchatMailTest extends SuggestionAchatTestCase {
 
   /** @test */
   public function mailSubjectShouldBeSuggestionAchatHarryPotter() {
-    $this->assertEquals('Suggestion d\'achat: Harry emPotté',
-                        quoted_printable_decode($this->_sent_mail->getSubject()));
+    $this->assertContains('Suggestion d\'achat: Harry emPotté',
+                          quoted_printable_decode($this->_sent_mail->getSubject()));
   }
 
 
diff --git a/tests/scenarios/RendezVous/RendezVousAdminTest.php b/tests/scenarios/RendezVous/RendezVousAdminTest.php
index 272fcff3d7cb799c67830afb3a602753b9fa177a..9b257a1a0281d1df22198b0d8870689e4665ed29 100644
--- a/tests/scenarios/RendezVous/RendezVousAdminTest.php
+++ b/tests/scenarios/RendezVous/RendezVousAdminTest.php
@@ -951,7 +951,7 @@ class RendezVousSendNotificationTest extends RendezVousNotificationTestCase {
   /** @test */
   public function batchSendRendezVousSentReportSubjectShouldBeRapportdeNotifications() {
     $this->assertContains('Rapport de notifications envoyées pour les rendez-vous',
-                          $this->_sent_mails[2]->getSubject());
+                          quoted_printable_decode($this->_sent_mails[2]->getSubject()));
   }
 
 
diff --git a/tests/scenarios/bookmarks/SearchTest.php b/tests/scenarios/bookmarks/SearchTest.php
index 431c26b4c7ee38ccbaf80e10b631d7eed80fbf07..8acd88ad415a4939235a341a08fc4fd3ebdb2bcc 100644
--- a/tests/scenarios/bookmarks/SearchTest.php
+++ b/tests/scenarios/bookmarks/SearchTest.php
@@ -584,7 +584,7 @@ class Bookmarks_SearchCosmogrammePhaseTest
   public function withRecordDiffShouldContainsLinkToFullDiff() {
     $mail = $this->_mail_transport->getSentMails()[0];
     $this->assertContains('/recherche/simple/expressionRecherche/Harry+Potter/bookmarked_search/8/bookmarked_version/2018-02-07_105048',
-                          $mail->getBodyText(true));
+                          quoted_printable_decode($mail->getBodyText(true)));
   }