diff --git a/FEATURES/160166 b/FEATURES/160166
new file mode 100644
index 0000000000000000000000000000000000000000..97d56fe39e731725e7e84c40b69386ac23d9cf92
--- /dev/null
+++ b/FEATURES/160166
@@ -0,0 +1,10 @@
+        '160166' =>
+            ['Label' => $this->_('Lettres d\'information : Les lettres d\'informations envoyées peuvent prendre une CSS qui permette de l\'afficher comme sur le site'),
+             'Desc' => '',
+             'Image' => '',
+             'Video' => '',
+             'Category' => 'Newsletters',
+             'Right' => function($feature_description, $user) {return true;},
+             'Wiki' => 'https://wiki.bokeh-library-portal.org/index.php?title=Lettre_d%27information',
+             'Test' => '',
+             'Date' => '2023-08-01'],
\ No newline at end of file
diff --git a/VERSIONS_WIP/160166 b/VERSIONS_WIP/160166
new file mode 100644
index 0000000000000000000000000000000000000000..c7dfe2ff33fbcd1d7d46d25a41a295f631beccb6
--- /dev/null
+++ b/VERSIONS_WIP/160166
@@ -0,0 +1 @@
+ - fonctionnalité #160166 : Lettres d'information : Les lettres d'informations envoyées peuvent prendre une CSS qui permette de l'afficher comme sur le site
\ No newline at end of file
diff --git a/cosmogramme/sql/patch/patch_453.php b/cosmogramme/sql/patch/patch_453.php
new file mode 100644
index 0000000000000000000000000000000000000000..7289a015a498eff3b1c292b14ed5d423b36cc6ed
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_453.php
@@ -0,0 +1,11 @@
+<?php
+$adapter = Zend_Db_Table_Abstract::getDefaultAdapter();
+
+try {
+  $adapter->query(
+                  'ALTER TABLE `newsletters` '
+                  . 'ADD COLUMN `display_full_article` tinyint(1) default 0 '
+                  . ',ADD COLUMN `render_with_widget` tinyint(1) default 0'
+                  . ',ADD COLUMN `custom_css` text default ""'
+  );
+} catch(Exception $e) {}
diff --git a/includes.php b/includes.php
index 1d731d90a6900f2463434f297ff627acd36df12f..484d64317547febfca1e8908b196c92025721bfb 100644
--- a/includes.php
+++ b/includes.php
@@ -21,8 +21,8 @@
 $base_path = realpath(dirname(__FILE__));
 set_include_path($base_path . PATH_SEPARATOR .
                  $base_path . '/library' . PATH_SEPARATOR .
-								 $base_path . '/library/storm/src' . PATH_SEPARATOR .
-								 $base_path . '/library/storm/zf/library' . PATH_SEPARATOR .
+                 $base_path . '/library/storm/src' . PATH_SEPARATOR .
+                 $base_path . '/library/storm/zf/library' . PATH_SEPARATOR .
                  $base_path . '/library/digital_resources' . PATH_SEPARATOR .
                  $base_path . '/library/templates' . PATH_SEPARATOR .
 								 get_include_path());
@@ -30,4 +30,4 @@ set_include_path($base_path . PATH_SEPARATOR .
 include_once "local.php";
 include_once "library/fonctions/fonctions.php";
 require_once "library/startup.php";
-?>
\ No newline at end of file
+?>
diff --git a/library/Class/Article.php b/library/Class/Article.php
index 9c560c55b2562424838e6036e0f04526104c109d..ed5b4117b2c043cd459c3052b47b2b770ce7595b 100644
--- a/library/Class/Article.php
+++ b/library/Class/Article.php
@@ -591,14 +591,15 @@ class Class_Article extends Storm_Model_Abstract {
    * @return string
    */
   public function getUrl() {
-    return ['controller' => 'cms',
+    return ['module' => 'opac',
+            'controller' => 'cms',
             'action' => 'articleview',
             'id' => $this->getId()];
   }
 
 
   public function getAbsoluteUrl() {
-    return Class_Url::absolute($this->getUrl());
+    return Class_Url::absolute($this->getUrl(), null, true);
   }
 
 
diff --git a/library/Class/Article/Loader.php b/library/Class/Article/Loader.php
index db423eeb6baf371f7d9879a79f95b6537ca92a9d..caca2782cc0703f21ac8bf98eacb23b569c62da4 100644
--- a/library/Class/Article/Loader.php
+++ b/library/Class/Article/Loader.php
@@ -94,9 +94,10 @@ class Class_Article_Loader extends Storm_Model_Loader {
       ->filterByCustomFields($preferences['custom_fields'])
       ->filterByTag($preferences['tag'])
       ->filterByDay($preferences['event_date'])
-      ->apply($this->_map_callback)
-      ->sortBy($select->getSortOrder())
-      ;
+      ->apply($this->_map_callback);
+
+    if (static::ORDER_SELECTION !== $select->getSortOrder())
+      $collection = $collection->sortBy($select->getSortOrder());
 
     $this->_all_articles = $collection->getArrayCopy();
 
diff --git a/library/Class/Newsletter.php b/library/Class/Newsletter.php
index bc6abac77f6b5fa8c1ea03d2dcf65af8a04b8b2d..e1b21a281a01cf1fc629b1a51b2d9b358678a59b 100644
--- a/library/Class/Newsletter.php
+++ b/library/Class/Newsletter.php
@@ -108,6 +108,9 @@ class Class_Newsletter extends Storm_Model_Abstract {
                                           'draft' => 0,
                                           'id_catalogue' => '',
                                           'id_panier' => '',
+                                          'display_full_article' => 0,
+                                          'render_with_widget' => 0,
+                                          'custom_css' => '',
                                           'articles_ids' => '',
                                           'articles_categories_ids' => '',
                                           'mail_subject' => '',
@@ -224,7 +227,7 @@ class Class_Newsletter extends Storm_Model_Abstract {
     if (!$user)
       return false;
 
-    return Class_Newsletter_Blacklist::isBlackListed($user->getMail(), $this->getId());
+    return Class_Newsletter_Blacklist::isBlackListed($user, $this->getId());
   }
 
 
@@ -298,7 +301,7 @@ class Class_Newsletter extends Storm_Model_Abstract {
       ($this->hasArticlesIds() || $this->hasArticlesCategoriesIds()
        ? Class_Article::getArticlesByPreferences(['id_items' => $this->getArticlesIds(),
                                                   'id_categorie' => $this->getArticlesCategoriesIds(),
-                                                  'display_order' => 'Selection'])
+                                                  'display_order' => Class_Article_Loader::ORDER_SELECTION])
        : []);
   }
 
@@ -331,11 +334,6 @@ class Class_Newsletter extends Storm_Model_Abstract {
   }
 
 
-  public function unsubscribeUser($user) {
-    $this->unsubscribeByMail($user->getMail());
-  }
-
-
   public function subscribeToDedicatedGroup($user) {
     $this->getDedicatedGroup()->addUserOptimized($user);
     return $this;
@@ -349,6 +347,8 @@ class Class_Newsletter extends Storm_Model_Abstract {
     if ($is_blacklisted) {
       Class_Newsletter_Blacklist::deleteBy(['newsletter_id' => $this->getId(),
                                             'mail' => $user->getMail()]);
+      Class_Newsletter_Blacklist::deleteBy(['newsletter_id' => $this->getId(),
+                                            'user_id' => $user->getId()]);
     }
 
     if (!$is_recipient)
@@ -358,10 +358,8 @@ class Class_Newsletter extends Storm_Model_Abstract {
   }
 
 
-  public function unsubscribeByMail($mail) {
-    return $mail
-      ? Class_Newsletter_Blacklist::unsubscribeByMail($mail, $this->getId())
-      : false;
+  public function unsubscribeUser(Class_Users $user, string $mail='') :bool {
+    return Class_Newsletter_Blacklist::unsubscribeUser($user, $this->getId(), $mail);
   }
 
 
@@ -453,10 +451,9 @@ class Class_Newsletter extends Storm_Model_Abstract {
 
   public function getFirstImageUrl() : string {
     $template = $this->newTemplate();
-    $text = $template->getBodyHTML();
 
     $matches = [];
-    return (preg_match('/< *img[^>]*src *= *["\']?([^"\'>]*)/i', $text, $matches) > 0)
+    return (preg_match('/< *img[^>]*src *= *["\']?([^"\'>]*)/i', $template->getRawHTML(), $matches) > 0)
       ? $matches[1]
       : '';
   }
diff --git a/library/Class/Newsletter/Blacklist.php b/library/Class/Newsletter/Blacklist.php
index 9d3001baf0c6ad2313946dc02bb4e9f203e84287..696767f1fcf7713e03120d27ab4eec33a03f6414 100644
--- a/library/Class/Newsletter/Blacklist.php
+++ b/library/Class/Newsletter/Blacklist.php
@@ -28,23 +28,31 @@ class Newsletter_BlacklistLoader extends Storm_Model_Loader {
   }
 
 
-  public function unsubscribeByMail($mail, $newsletter_id) {
-    if (0 < Class_Newsletter_Blacklist::countBy(['newsletter_id' => $newsletter_id,
-                                                 'mail' => $mail]))
-        return;
+  public function unsubscribeUser(Class_Users $user, int $newsletter_id, string $mail = '') :bool {
+    if (Class_Newsletter_Blacklist::isBlackListed($user, $newsletter_id))
+      return false;
+
+    if (!$mail)
+      $mail = $user->getMail() ?? '';
 
-    $blacklist = Class_Newsletter_Blacklist::newInstance(['mail' => $mail,
+    $blacklist = Class_Newsletter_Blacklist::newInstance(['user_id' => $user->getId(),
+                                                          'mail' => $mail,
                                                           'newsletter_id' => $newsletter_id]);
 
     return $blacklist->save();
   }
 
 
-  public function isBlackListed($mail, $newsletter_id) {
-    if (!$mail)
+  public function isBlackListed(Class_Users $user, int $newsletter_id) :bool{
+    if (!$user)
       return false;
-    return Class_Newsletter_Blacklist::findFirstBy(['newsletter_id' => $newsletter_id,
-                                                    'mail' => $mail]);
+    if (0 < Class_Newsletter_Blacklist::countBy(['newsletter_id' => $newsletter_id,
+                                                 'user_id' => $user->getId()]))
+        return true;
+
+    return (($mail = $user->getMail())
+            && (0 < Class_Newsletter_Blacklist::countBy(['newsletter_id' => $newsletter_id,
+                                                         'mail' => $mail])));
   }
 }
 
diff --git a/library/Class/Newsletter/TemplateHelper.php b/library/Class/Newsletter/TemplateHelper.php
index 09736da977a126e323cf97b62fe4a76d833a1ba3..2bf3e6a26314ca00de8607c8aaf5d7050e047170 100644
--- a/library/Class/Newsletter/TemplateHelper.php
+++ b/library/Class/Newsletter/TemplateHelper.php
@@ -22,7 +22,7 @@
 
 class Class_Newsletter_TemplateHelper {
 
-
+  use Trait_StormFileSystem;
   const URL_PLACEHOLDER = '{{URL}}';
 
 
@@ -90,18 +90,32 @@ class Class_Newsletter_TemplateHelper {
       return $this->_body_html_cache;
 
     $html = $this->_renderNewsletterWith('_getContentAsHTML',
-                                         'renderHtml',
+                                         ($this->_newsletter->getRenderWithWidget())
+                                         ? '_renderWithWidget'
+                                         : 'renderHTML',
                                          '_getUnsubscribeHTML');
 
     return $this->_body_html_cache = $this->_inlineCSS($html);
   }
 
 
+  public function getRawHTML() : string {
+    if ( $this->_body_html_cache )
+      return $this->_body_html_cache;
+
+    return $this->_body_html_cache = $this->_renderNewsletterWith('_getContentAsHTML',
+                                         'renderHtml',
+                                         '_getUnsubscribeHTML');
+  }
+
+
   protected function _inlineCSS(string $html) : string {
     if (Class_AdminVar::isModuleEnabled('NEWSLETTER_INLINE_CSS')) {
       require('emogrifier/vendor/autoload.php');
-      return Pelago\Emogrifier\CssInliner::fromHtml($html)
-        ->inlineCss()
+      $css_inliner = Pelago\Emogrifier\CssInliner::fromHtml($html);
+
+      return $this
+        ->_addCssLinks($css_inliner)
         ->render();
     }
 
@@ -109,14 +123,57 @@ class Class_Newsletter_TemplateHelper {
   }
 
 
+  protected function _addCssLinks(Pelago\Emogrifier\CssInliner $css_inliner) : Pelago\Emogrifier\CssInliner {
+    if (!$this->_newsletter->getRenderWithWidget())
+      return $css_inliner->inlineCss();
+
+    $css_links =
+      ['/library/templates/Intonation/Assets/css/intonation.css',
+       '/public/opac/css/global.css',
+       '/library/templates/Intonation/Assets/Bootstrap/bootstrap-4.3.1-dist/css/bootstrap.min.css',
+       '/public/opac/css/font-awesome-4.7.0/css/font-awesome.css'
+      ];
+
+    if ($this->getFileSystem()
+        ->fileExists( $_SERVER['DOCUMENT_ROOT'] . $this->_newsletter->getCustomCss()))
+      $css_links[] = $this->_newsletter->getCustomCss();
+
+    array_walk($css_links,
+               function($link) use ($css_inliner) {
+                 if ($css = $this
+                     ->getFileSystem()
+                     ->fileGetContents($_SERVER['DOCUMENT_ROOT'] . $link))
+                   $css_inliner->inlineCss($css);
+               });
+
+    return $css_inliner;
+  }
+
+
   protected function _renderNewsletterWith(string $mail_content_function,
                                            string $mail_renderer_function,
                                            string $unsubscribe_function,
                                            string $implode_callback = '') : string {
-    $content = [call_user_func([$this, $mail_content_function])];
+
+    $content = [ call_user_func([$this, $mail_content_function]),
+                 ...$this->_renderContent($mail_renderer_function),
+                 call_user_func([$this, $unsubscribe_function])];
+
+    return $implode_callback
+      ? call_user_func([$this, $implode_callback], $content)
+      : implode($content);
+  }
+
+
+  protected function _renderContent(string $mail_renderer_function) :array {
+    if ($mail_renderer_function == '_renderWithWidget')
+      return $this->_renderWithWidget();
+
     $records = $this->_getRecords();
+
     $articles = $this->_getArticles();
 
+    $content = [];
 
     $renderer = new Class_Notice_MailRenderer;
     foreach($records as $record)
@@ -126,11 +183,30 @@ class Class_Newsletter_TemplateHelper {
     foreach($articles as $article)
       $content [] = call_user_func([$renderer, $mail_renderer_function], $article);
 
-    $content [] = call_user_func([$this, $unsubscribe_function]);
+    return $content;
+  }
+
 
-    return $implode_callback
-      ? call_user_func([$this, $implode_callback], $content)
-      : implode($content);
+  protected function _renderWithWidget() :array {
+    $view = (new ZendAfi_Controller_Action_Helper_View)->init();
+    $widget = (new Class_Systeme_Widget_Widget)
+      ->loadFromSettings(['type_module' => Class_Systeme_ModulesAccueil_News::CODE,
+                          'profile_id' => 1,
+                          'preferences' =>
+                          ['layout' => 'list',
+                           'rendering' => 'card-horizontal',
+                           'description_html' => $this->_newsletter->getDisplayFullArticle(),
+                           'id_items' => $this->_newsletter->getArticlesIds(),
+                           'id_categorie' => $this->_newsletter->getArticlesCategoriesIds(),
+                           'display_order'  => Class_Systeme_ModulesAccueil_News::SELECTION
+                          ]
+                          ]);
+
+    $content [] = (new Intonation_Template)
+      ->addHelperPath($view)
+      ->renderWidget($widget, $view);
+
+    return $content;
   }
 
 
diff --git a/library/Class/Systeme/ModulesAccueil/DomainBrowser.php b/library/Class/Systeme/ModulesAccueil/DomainBrowser.php
index bfd86ad1c6aec5e3291e2d076304e97a53398c07..473845a45e1444f89b5a9cfc6818bd2231f012db 100644
--- a/library/Class/Systeme/ModulesAccueil/DomainBrowser.php
+++ b/library/Class/Systeme/ModulesAccueil/DomainBrowser.php
@@ -31,11 +31,11 @@ class Class_Systeme_ModulesAccueil_DomainBrowser extends Class_Systeme_ModulesAc
 
   public function __construct() {
     $this->_libelle = $this->_('Boite domaines');
-    $this->_form = 'ZendAfi_Form_Configuration_Widget_Domains';
+    $this->_form = ZendAfi_Form_Configuration_Widget_Domains::class;
     $this->_defaultValues = ['titre' => $this->_libelle,
                              'allow_breadcrumb' => 0,
                              'root_domain_id' => 0,
                              'tri' => Class_CriteresRecherche::SORT_PUBLICATION_DESC,
                              'display_mode' => Class_Systeme_ModulesAppli::LISTE_FORMAT_MUR];
   }
-}
\ No newline at end of file
+}
diff --git a/library/Class/Systeme/ModulesAccueil/News.php b/library/Class/Systeme/ModulesAccueil/News.php
index d0a9fb8c18d882c2b16a7597c02df6642c00cdb6..7330b973c6f8eb020198415e5b2b7d8e41bf4b69 100644
--- a/library/Class/Systeme/ModulesAccueil/News.php
+++ b/library/Class/Systeme/ModulesAccueil/News.php
@@ -40,7 +40,7 @@ class Class_Systeme_ModulesAccueil_News extends Class_Systeme_ModulesAccueil_Nul
 
   public function __construct() {
     $this->_libelle = $this->_('Boite articles');
-    $this->_form = 'ZendAfi_Form_Configuration_Widget_Articles';
+    $this->_form = ZendAfi_Form_Configuration_Widget_Articles::class;
     $this->_defaultValues = ['titre' => $this->_libelle,
                              'anchor' => '',
                              'allow_link_on_title' => false,
@@ -66,4 +66,4 @@ class Class_Systeme_ModulesAccueil_News extends Class_Systeme_ModulesAccueil_Nul
             static::COMMENTS => $this->_('par nombre d\'avis'),
             static::RANDOM => $this->_('par ordre aléatoire')];
   }
-}
\ No newline at end of file
+}
diff --git a/library/Class/Users.php b/library/Class/Users.php
index 8b09589125c47e3d24acd410ea794cd9dce83355..cfd1e4cf9c80018a47c6441dd1210f7139144704 100644
--- a/library/Class/Users.php
+++ b/library/Class/Users.php
@@ -1702,7 +1702,7 @@ class Class_Users extends Storm_Model_Abstract {
     foreach (Class_Newsletter::findAll() as $newsletter) {
       Class_UserGroupMembership::deleteBy(['user_id' => $this->getId(),
                                            'user_group_id' => $newsletter->getDedicatedGroup()->getId()]);
-      Class_Newsletter_Blacklist::unsubscribeByMail($this->getMail(), $newsletter->getId());
+      Class_Newsletter_Blacklist::unsubscribeUser($this, $newsletter->getId());
     }
     return $this;
   }
diff --git a/library/ZendAfi/Controller/Action/Helper/View.php b/library/ZendAfi/Controller/Action/Helper/View.php
index 9324269ca238cf87e42e25ee85e2324af1296641..6d18def6210c34223d8412aca409f742b7ff12a6 100644
--- a/library/ZendAfi/Controller/Action/Helper/View.php
+++ b/library/ZendAfi/Controller/Action/Helper/View.php
@@ -42,7 +42,7 @@ class ZendAfi_Controller_Action_Helper_View extends Zend_View {
     $this->setEscape('htmlentities');
 
     $this->doctype('HTML5');
-
+    return $this;
   }
 
 
diff --git a/library/ZendAfi/Form/Admin/Newsletter.php b/library/ZendAfi/Form/Admin/Newsletter.php
index 9f905bb3f5e9833f3007f514f866e1129d8195b4..49b54c2290fbc661ff9d23442a434441f89f18f4 100644
--- a/library/ZendAfi/Form/Admin/Newsletter.php
+++ b/library/ZendAfi/Form/Admin/Newsletter.php
@@ -87,6 +87,32 @@ class ZendAfi_Form_Admin_Newsletter extends ZendAfi_Form {
     parent::populate($datas);
 
     $this
+      ->addElement('radio',
+                   'display_full_article',
+                   ['label' => $this->_('Afficher articles en intégralité'),
+                    'value' => $datas['display_full_article'] ?? 0,
+                    'separator' => '',
+                    'multiOptions' => [ '1' => $this->_('Oui'),
+                                        '0' => $this->_('Non')
+                    ]
+                   ])
+      ->addElement('radio',
+                   'render_with_widget',
+                   ['label' => $this->_('Afficher comme sur le site'),
+                    'value' => $datas['render_with_widget'] ?? 0,
+                    'separator' => '',
+                    'multiOptions' => [ '1' => $this->_('Oui'),
+                                        '0' => $this->_('Non')
+                    ]
+
+                   ])
+
+      ->addElement('userfile',
+                   'custom_css',
+                   ['label' => $this->_('Css personnalisée'),
+                    'value' => $datas['custom_css'] ?? '',
+                   ])
+
       ->addElement('treeSelect',
                    'articles_selector',
                    ['UrlDataSource' => Class_Url::assemble(['module' => 'admin',
@@ -111,7 +137,7 @@ class ZendAfi_Form_Admin_Newsletter extends ZendAfi_Form {
 
                     ]);
 
-    $this->addDisplayGroup(['articles_selector'],
+    $this->addDisplayGroup(['render_with_widget','display_full_article','custom_css','articles_selector'],
                            'articles',
                            ['legend' => $this->_('Articles')]);
     return $this;
diff --git a/library/storm b/library/storm
index dbf4e49cca70f9d469d1dc8e9949eddc0d9af0e7..704b04ef975b49729105805ef20e8835aafd18de 160000
--- a/library/storm
+++ b/library/storm
@@ -1 +1 @@
-Subproject commit dbf4e49cca70f9d469d1dc8e9949eddc0d9af0e7
+Subproject commit 704b04ef975b49729105805ef20e8835aafd18de
diff --git a/library/templates/Intonation/Library/View/Wrapper/Article.php b/library/templates/Intonation/Library/View/Wrapper/Article.php
index fd28d92fa57df94c034be5f53cb683a2741271f6..8eada298a423eafeb8778c2ce13bb5dca69e5ab1 100644
--- a/library/templates/Intonation/Library/View/Wrapper/Article.php
+++ b/library/templates/Intonation/Library/View/Wrapper/Article.php
@@ -52,7 +52,7 @@ class Intonation_Library_View_Wrapper_Article extends Intonation_Library_View_Wr
 
   public function getMainLink() {
     return (new Intonation_Library_Link)
-      ->setUrl(Class_Url::relative($this->_model->getUrl()))
+      ->setUrl($this->_model->getAbsoluteUrl())
       ->setImage($this->getIco('read-document', 'library'))
       ->setText($this->_('Lire la suite'))
       ->setScreenReaderText($this->_getMainLinkTitle());
@@ -70,7 +70,7 @@ class Intonation_Library_View_Wrapper_Article extends Intonation_Library_View_Wr
 
 
   public function getPicture() {
-    return $this->_model->getFirstImageRelativeURL();
+    return $this->_model->getFirstImageAbsoluteURL();
   }
 
 
diff --git a/library/templates/Intonation/Library/View/Wrapper/Newsletter.php b/library/templates/Intonation/Library/View/Wrapper/Newsletter.php
index 410dcfb56013f901fcd9686fe9f0595d9d287d11..cb0e532b7837cbce4a18e28ec8f9bdb6ee1218a2 100644
--- a/library/templates/Intonation/Library/View/Wrapper/Newsletter.php
+++ b/library/templates/Intonation/Library/View/Wrapper/Newsletter.php
@@ -99,13 +99,13 @@ class Intonation_Library_View_Wrapper_Newsletter extends Intonation_Library_View
 
   public function getDescription() {
     $template = $this->_model->newTemplate();
-    return $this->_truncate($template->getBodyHTML());
+    return $this->_truncate($template->getRawHTML());
   }
 
 
   public function getFullDescription() {
     $template = $this->_model->newTemplate();
-    return $template->getBodyHTML();
+    return $template->getRawHTML();
   }
 
 
diff --git a/public/opac/css/newsletter.css b/public/opac/css/newsletter.css
new file mode 100644
index 0000000000000000000000000000000000000000..b188bf0231990ab0954f3c59f948db6d19d9a29a
--- /dev/null
+++ b/public/opac/css/newsletter.css
@@ -0,0 +1,41 @@
+.cardify_horizontal_img{
+    max-width: 33% !important;
+}
+.cardify_horizontal_img img{
+    width: 100% !important;
+}
+.cardify_horizontal_content {
+    background-color: #f0a69e !important;
+}
+
+.cardify_horizontal_actions {
+    background-color: #f0a69e !important;
+}
+
+.cardify_horizontal_content .card-title a{
+    font-family: 'campton' !important;
+    font-weight: 900 !important;
+    font-size: 30px !important;
+    color: #005445 !important;
+    
+}
+.card-title a:first-letter{
+    text-transform: uppercase !important;
+}
+.badge-group .badge_tag .badge_text{
+    background-color: #005445 !important;
+    color: #ffffff !important;
+    padding: 5px 10px 5px 10px;
+}
+.card_action a.card-link{
+    background-color: #005445 !important;
+    color: #ffffff !important;
+    text-align: end !important;
+    font-size: larger !important;
+}
+div.widget-header{
+    display: none;
+}
+div.card_action.\31{
+    display: none;
+}
diff --git a/scripts/sendNewsletter.php b/scripts/sendNewsletter.php
index a90e862f4877919ab885d9686dfe0d932592ecb0..97f01911b9d69c39d8efa1282aa8abb3cf4c15c3 100644
--- a/scripts/sendNewsletter.php
+++ b/scripts/sendNewsletter.php
@@ -26,6 +26,8 @@ $dispatch_id = $argv[4];
 
 require_once 'includes.php';
 
+$_SERVER['DOCUMENT_ROOT'] = (new Storm_FileSystem_Disk)->getcwd();
+
 $bokeh = (new Bokeh_Engine())->warmUp();
 if ('test' != $dispatch_id
     && (!$dispatch = Class_Newsletter_Dispatch::find($dispatch_id))) {
@@ -47,4 +49,4 @@ register_shutdown_function($my_shutdown);
 $bokeh->powerOn();
 
 if ($dispatch)
-  $dispatch->sendBy(20);
\ No newline at end of file
+  $dispatch->sendBy(20);
diff --git a/tests/application/modules/admin/controllers/NewsletterControllerTest.php b/tests/application/modules/admin/controllers/NewsletterControllerTest.php
index 8c0476c98f2d854b20b6306435109d2c0a760c62..1fea20afbc16ae77bb22015006718d5395344dc3 100644
--- a/tests/application/modules/admin/controllers/NewsletterControllerTest.php
+++ b/tests/application/modules/admin/controllers/NewsletterControllerTest.php
@@ -410,6 +410,36 @@ class Admin_NewsletterControllerEditActionTest extends Admin_NewsletterControlle
     $this->assertXPath('//form//input[@name="articles_ids"][@value="6-42"]');
     $this->assertXPath('//form//input[@name="articles_categories_ids"][@value=""]');
   }
+
+
+  /** @test */
+  public function selectorForDisplayFullArticleShouldBePresent() {
+    $this->assertXPath('//form//input[@type="radio"][@name="display_full_article"][@value="0"]');
+    $this->assertXPath('//form//input[@type="radio"][@name="display_full_article"][@value="1"]');
+    $this->assertXPathContentContains('//label[@for="display_full_article"]','Afficher articles en intégralité');
+  }
+
+
+  /** @test */
+  public function selectorForRenderWithWidgetShouldBePresent() {
+    $this->assertXPath('//form//input[@type="radio"][@name="render_with_widget"][@value="0"]');
+    $this->assertXPath('//form//input[@type="radio"][@name="render_with_widget"][@value="1"]');
+    $this->assertXPathContentContains('//label[@for="render_with_widget"]','Afficher comme sur le site');
+  }
+
+
+  /** @test */
+  public function inputTextForCustomCssShouldBePresent() {
+    $this->assertXPath('//form//input[@type="text"][@name="custom_css"][@value=""]');
+    $this->assertXPathContentContains('//label[@for="custom_css"]','Css personnalisée');
+  }
+
+
+  /** @test */
+  public function buttonOpenFileManagerForCustomCssShouldBePresent() {
+    $this->assertXPathContentContains('//button[contains(@onclick,"openFileManagerFor_custom_css()")]',
+                                      'Explorer le serveur');
+  }
 }
 
 
@@ -970,7 +1000,7 @@ abstract class Admin_NewsletterControllerPreviewActionTestCase
                                       'libelle' => 'Portail',
                                       'mail_site' => 'laurent@afi-sa.net']);
 
-    $this->onLoaderOfModel('Class_Article')
+    $this->onLoaderOfModel(Class_Article::class)
          ->whenCalled('getArticlesByPreferences')
          ->answers([$le_roi_des_cons,
                     $septante_millions,
@@ -989,10 +1019,22 @@ class Admin_NewsletterControllerPreviewActionWithArticlesSelectionTest
     parent::setUp();
 
     Class_AdminVar::set('NEWSLETTER_INLINE_CSS', '1');
+    Class_Newsletter_TemplateHelper::setFileSystem($this->mock()
+                                                   ->whenCalled('fileGetContents')
+                                                   ->answers('')
+                                                   ->whenCalled('fileExists')
+                                                   ->answers(true));
     $this->dispatch('/admin/newsletter/preview/id/3');
   }
 
 
+  public function tearDown(){
+    Class_AdminVar::set('NEWSLETTER_INLINE_CSS', 0);
+    Class_Newsletter_TemplateHelper::setFileSystem(null);
+    parent::tearDown();
+  }
+
+
   /** @test */
   public function fromShouldBeLaurentAtAfiSaDotNet() {
     $this->assertQueryContentContains('p', 'laurent@afi-sa.net');
@@ -2163,3 +2205,51 @@ class Admin_NewsletterControllerShowStatusActionTest
     $this->fail('should have 404 error');
   }
 }
+
+
+
+
+class Admin_NewsletterControllerPreviewActionWithTemplateLayoutAndRenderingSelectionTest
+  extends Admin_NewsletterControllerPreviewActionTestCase {
+  protected $_filesystem;
+
+  public function setUp() {
+    parent::setUp();
+    Class_AdminVar::set('NEWSLETTER_INLINE_CSS', '1');
+    $this->_buildTemplateProfil(['id' => 1]);
+
+    $_SERVER['DOCUMENT_ROOT']='.';
+
+    Class_Newsletter::find(3)->setRenderWithWidget(true)
+                             ->setCustomCss('/newsletter.css')
+                             ->save();
+
+    $this->_filesystem = (new Storm_FileSystem_Volatile)
+      ->filePutContents($_SERVER['DOCUMENT_ROOT'].'/newsletter.css',
+                        '.card-title{color: "red"; font-weight: "bolder";}');
+
+    Class_Newsletter_TemplateHelper::setFileSystem($this->_filesystem);
+    $this->dispatch('/admin/newsletter/preview/id/3');
+  }
+
+
+  /** @test */
+  public function cardTitleShouldContainsLeRoiDesCons() {
+    $this->assertXPathContentContains('//div[@class="list-group"]//div[contains(@class,"card-title")][contains(@style,\'color: "red"; font-weight: "bolder"\')]'
+                                      , 'Le Roi des cons');
+  }
+
+
+  /** @test */
+  public function cardDescriptionShouldContainsIlEstBeauIlEstFier() {
+    $this->assertXPathContentContains('//div[@class="card"]//p[@class="model_description_Class_Article"]'
+                                      , 'Il est beau, il est fier');
+  }
+
+
+  /** @test */
+  public function cardBadgeShouldContains() {
+    $this->assertXPathContentContains('//div[@class="card"]//div[contains(@class,"badge-group")]//span[contains(@class,"badge_text")]'
+                                      , 'La France');
+  }
+}
diff --git a/tests/application/modules/opac/controllers/AbonneControllerNewslettersTest.php b/tests/application/modules/opac/controllers/AbonneControllerNewslettersTest.php
index b7cfb15abd8c59774d79d7ddc060f99f0e59c2e6..df29ec862c2b02abc863000d7b9f6b4823a19953 100644
--- a/tests/application/modules/opac/controllers/AbonneControllerNewslettersTest.php
+++ b/tests/application/modules/opac/controllers/AbonneControllerNewslettersTest.php
@@ -749,7 +749,7 @@ class AbonneControllerNewslettersMultipleSubscriptionTest extends AbstractContro
     ZendAfi_Auth::getInstance()->logUser($user);
     (new NewsletterFixtures())->createUsersAndNewsletter($this);
 
-    Class_Newsletter_Blacklist::unsubscribeByMail($user->getMail(), 1);
+    Class_Newsletter_Blacklist::unsubscribeUser($user, 1);
     $this->dispatch('/opac/abonne/subscribe-newsletter/id/1',true);
   }
 
@@ -768,4 +768,85 @@ class AbonneControllerNewslettersMultipleSubscriptionTest extends AbstractContro
                        Class_Newsletter_Blacklist::findAllBy(['mail' => 'pat@pat.info',
                                                               'newsletter_id' => 1]));
   }
-}
\ No newline at end of file
+}
+
+
+
+
+class AbonneControllerNewslettersUserWithoutMailTest extends AbstractControllerTestCase {
+  public function setUp() {
+    parent::setUp();
+    $_SERVER['HTTP_REFERER'] = '/opac/index';
+
+    $user = $this->fixture(Class_Users::class,
+                           ['id' => 156,
+                            'login' => 'tomato',
+                            'password' => 'pwd',
+                            'mail' => '']);
+
+    ZendAfi_Auth::getInstance()->logUser($user);
+    (new NewsletterFixtures())->createUsersAndNewsletter($this);
+
+    Class_Newsletter_Blacklist::unsubscribeUser($user, 1);
+    $this->dispatch('/opac/abonne/subscribe-newsletter/id/1');
+  }
+
+
+  /** @test **/
+  public function tomatoShouldBeSubscribe() {
+    $this
+      ->assertNotNull(Class_UserGroupMembership::findFirstBy(['user_id' => 156,
+                                                              'user_group_id' => Class_Newsletter::find(1)->getDedicatedGroup()->getId()]));
+  }
+
+
+  /** @test */
+  public function tomatoMailShouldNotBeBlacklisted() {
+    $this->assertCount(0,
+                       Class_Newsletter_Blacklist::findAllBy(['user_id' => 156,
+                                                              'newsletter_id' => 1]));
+  }
+}
+
+
+
+
+class AbonneControllerNewslettersUnsubscribeUserWithoutMailTest extends AbstractControllerTestCase {
+  public function setUp() {
+    parent::setUp();
+    $_SERVER['HTTP_REFERER'] = '/opac/index';
+
+    $user = $this->fixture(Class_Users::class,
+                           ['id' => 156,
+                            'login' => 'tomato',
+                            'password' => 'pwd',
+                            'mail' => '']);
+
+    (new NewsletterFixtures())->createUsersAndNewsletter($this);
+    xdebug_break();
+    $user->subscribeNewsletter(Class_Newsletter::find(1));
+    ZendAfi_Auth::getInstance()->logUser($user);
+    $this->dispatch('/opac/abonne/unsubscribe-newsletter/id/1');
+  }
+
+
+  /** @test **/
+  public function tomatoShouldBeSubscribe() {
+    $this
+      ->assertNotNull(Class_UserGroupMembership::findFirstBy(['user_id' => 156,
+                                                              'user_group_id' => Class_Newsletter::find(1)->getDedicatedGroup()->getId()]));
+  }
+
+
+  /** @test */
+  public function userTomatoShouldBeBlacklistedForNewsletterOne() {
+    $this->assertTrue( Class_Newsletter_Blacklist::isBlacklisted(Class_Users::find(156),
+                                                                 1));
+  }
+
+
+  /** @test */
+  public function flashMessengerShouldContains() {
+    $this->assertFlashMessengerContentContains('Vous êtes désinscrit de la liste de diffusion: Nouveautés classique');
+  }
+}
diff --git a/tests/application/modules/telephone/controllers/IndexControllerTest.php b/tests/application/modules/telephone/controllers/IndexControllerTest.php
index f7f0d750765706063ff83dfb780cc36667c5a673..3a7072d3296817575588434ed5612db88eec6e50 100644
--- a/tests/application/modules/telephone/controllers/IndexControllerTest.php
+++ b/tests/application/modules/telephone/controllers/IndexControllerTest.php
@@ -530,7 +530,7 @@ class IndexControllerTelephoneEmbedModuleTest extends AbstractIndexControllerTel
 
   /** @test */
   function articleErikTruffazUrlShouldKeepModuleEmbed() {
-    $this->assertXPath('//ul[@class="listview-news"]//a[contains(@href, "/embed/cms/articleview/id/3")]', $this->_response->getBody());
+    $this->assertXPath('//ul[@class="listview-news"]//a[contains(@href, "/embed/cms/articleview/module/opac/id/3")]');
   }
 
 
diff --git a/tests/db/UpgradeDBTest.php b/tests/db/UpgradeDBTest.php
index 1207e4eedc714e5eeea7d6f509407409f6277b55..82e0d278e8e3ee34ca05299439d5f2c61d50ffbe 100644
--- a/tests/db/UpgradeDBTest.php
+++ b/tests/db/UpgradeDBTest.php
@@ -5304,3 +5304,34 @@ class UpgradeDB_452_Test extends UpgradeDBTestCase {
   /** @test */
   public function placeholderForCommSigbOrpheePatch() {}
 }
+
+
+
+
+class UpgradeDB_453_Test extends UpgradeDBTestCase {
+  public function prepare(){
+    try {
+      $this->query("ALTER TABLE newsletters DROP display_full_article");
+      $this->query("ALTER TABLE newsletters DROP render_with_widget");
+      $this->query("ALTER TABLE newsletters DROP custom_css");
+    } catch(Exception $e) {}
+  }
+
+
+  /** @test */
+  public function displayFullArticleColumnInTableNewsletterShouldExist() {
+    $this->assertFieldType('newsletters','display_full_article', 'tinyint(1)');
+  }
+
+
+  /** @test */
+  public function renderWithWidgetColumnInTableNewsletterShouldExist() {
+    $this->assertFieldType('newsletters','render_with_widget', 'tinyint(1)');
+  }
+
+
+  /** @test */
+  public function customCssColumnInTableNewsletterShouldBeText() {
+    $this->assertFieldType('newsletters','custom_css', 'text');
+  }
+}
diff --git a/tests/fixtures/NewsletterFixtures.php b/tests/fixtures/NewsletterFixtures.php
index c8567bf85d11c3d88c63881bed26f2baa91f0013..497ab2d094d21f1b11422c6fae4b3d00ea5c533c 100644
--- a/tests/fixtures/NewsletterFixtures.php
+++ b/tests/fixtures/NewsletterFixtures.php
@@ -51,7 +51,7 @@ class NewsletterFixtures {
                                       'libelle' => 'My Group',
                                       'users' => [$pat, $laurent]]);
 
-    Class_Newsletter_Blacklist::unsubscribeByMail($anonymous->getMail(),-1);
+    Class_Newsletter_Blacklist::unsubscribeUser($anonymous,-1);
   }
 
 
diff --git a/tests/library/Class/ArticleTest.php b/tests/library/Class/ArticleTest.php
index 7ef76fc0fbda6320282808fb2d642f6e726cbd7a..c7b91e93a0b0d7f3413be0125a3d65063afdeb7d 100644
--- a/tests/library/Class/ArticleTest.php
+++ b/tests/library/Class/ArticleTest.php
@@ -409,7 +409,8 @@ class ArticleTestSmallArticle extends ModelTestCase {
 
   /** @test **/
   public function urlProfilShoulNotContainProfil() {
-    $this->assertEquals(['controller' => 'cms',
+    $this->assertEquals(['module'=> 'opac',
+                         'controller' => 'cms',
                          'action' => 'articleview',
                          'id' => '0'],
                         $this->_article->getUrl());
diff --git a/tests/library/Class/NewsletterMailingTest.php b/tests/library/Class/NewsletterMailingTest.php
index ae0b7e2bd42efbc34826a53e5d1f47aa699ce45a..22937c52ead8482f48ea73dd97171e291ae5580c 100644
--- a/tests/library/Class/NewsletterMailingTest.php
+++ b/tests/library/Class/NewsletterMailingTest.php
@@ -122,7 +122,7 @@ abstract class NewsletterMailingTestCase extends ModelTestCase {
                   $this->zorkglub,
                   $anonymous])
       ->save();
-    Class_Newsletter_Blacklist::unsubscribeByMail($anonymous->getMail(), 1);
+    Class_Newsletter_Blacklist::unsubscribeUser($anonymous, 1);
 
     $this->onLoaderOfModel('Class_Notice')
          ->whenCalled('getNoticesFromPreferences')
@@ -645,3 +645,190 @@ class NewsletterMailingRecordAbsoluteUrlTest extends ModelTestCase {
     return Class_Url::absolute('/recherche/viewnotice/clef//id/' . $id);
   }
 }
+
+
+
+
+
+/** @see http://forge.afi-sa.fr/issues/177221 */
+class NewsletterMailingRecordKeepingWidgetTest extends ModelTestCase {
+  protected $_storm_default_to_volatile=true;
+  protected
+    $_text_content = '',
+    $_html_content = '',
+    $_xpath;
+
+
+  public function setUp() {
+    parent::setUp();
+
+    Class_AdminVar::set('NEWSLETTER_INLINE_CSS',1);
+
+    Zend_Registry::set('sql',
+                       $this->mock()
+                       ->whenCalled('fetchAllByColumn')
+                       ->with('select distinct(bib_admin_users.mail) from bib_admin_users where disable_newsletter=1 and mail<>"" and mail is not null')
+                       ->answers([]));
+
+    $this->_xpath = new Storm_Test_XPath();
+    $_SERVER['DOCUMENT_ROOT'] = '/var/www/html';
+
+    $time_source = new TimeSourceForTest('2014-05-23 14:30:00');
+    Class_Newsletter::setTimeSource($time_source);
+    Class_UserGroup::setMemoryCleaner(function() {});
+    $this->alcor = $this->fixture(Class_Users::class,
+                                  ['id' => 120,
+                                   'login' => 'alc',
+                                   'password' => 'or',
+                                   'mail' => 'procyon@centre-de-recherche.fr']);
+
+    $this->_letter = $this->fixture(Class_Newsletter::class,
+                                    ['id' => 23,
+                                     'titre' => 'Alerte vega',
+                                     'mail_subject' => 'notification',
+                                     'id_panier' => 0,
+                                     'nb_notices' => 50,
+                                     'id_catalogue' => 0,
+                                     'articles_ids' => '1-3-12',
+                                     'display_full_article' => 1,
+                                     'render_with_widget' => 1,
+                                     'custom_css' => '/userfiles/css/newsletter.css',
+                                     'expediteur' => 'professeur@centre-de-recherche.fr',
+                                     'contenu' => 'Golgoth aperçu azimut 234.53',
+                                     'last_distribution_date' => '',
+                                     ]);
+    $this->_letter->getDedicatedGroup()->setUsers([$this->alcor])->save();
+    Class_Newsletter_TemplateHelper::setFileSystem($this->mock()
+                                                   ->whenCalled('fileGetContents')
+                                                   ->with($_SERVER['DOCUMENT_ROOT'] . '/userfiles/css/newsletter.css')
+                                                   ->answers(':root{}
+.event_tag{box-sizing: border-box; margin-bottom: .5rem; margin-left: 0;}
+.event_start_date{box-sizing: border-box; margin-bottom: .5rem; margin-left: 0;}')
+                                                   ->whenCalled('fileExists')
+                                                   ->with($_SERVER['DOCUMENT_ROOT'] . '/userfiles/css/newsletter.css')
+                                                   ->answers(true)
+                                                   ->whenCalled('fileGetContents')
+                                                   ->answers(''));
+
+    $articles  =
+      [
+       $this->fixture(Class_Article::class,
+                      ['id' => 3,
+                       'titre' => 'joies du printemps',
+                       'description' =>'<img src="animage-1.png"><strong>Les oiseaux chantent encore</strong><a href="https://linuxfr.org">les joies du code</a>',
+                       'contenu' =>'<img src="animage-1.jpg"><strong>Les oiseaux chantent encore</strong><a href="https://linuxfr.org">les joies du code</a>',
+                       'status' => Class_Article::STATUS_VALIDATED,
+                       'debut' => '2012-06-06 09:00:00',
+                       'fin' => '2045-06-06 09:00:00'
+                      ]),
+       $this->fixture(Class_Article::class,
+                      ['id' => 1,
+                       'titre' => 'festival du film d\'animation',
+                       'description' => '<img src="animage-2.png"><strong>Spiderman</strong><a href="https://linuxfr.org">les joies du code</a>',
+                       'contenu' => '<img src="animage-2.jpg"><strong>Superman</strong><a href="https://linuxfr.org">les joies du code</a>',
+                       'status' => Class_Article::STATUS_VALIDATED,
+                       'debut' => '2012-06-06 09:00:00',
+                       'fin' => '2045-06-06 09:00:00',
+                       'events_debut' => '2014-06-01 09:00:00',
+                       'events_fin' => '2014-06-03 09:00:00',
+                       'tags' => 'Jeunesse;Vieillesse;animation'
+                      ]),
+
+       $this->fixture(Class_Article::class,
+                      ['id' => 12,
+                       'titre' => 'News Selectionnée Mais Ancienne Non affichée',
+                       'description' => '<img src="animage2.png"><strong>Spiderman</strong><a href="https://linuxfr.org">les joies du code</a>',
+                       'contenu' => '<img src="animage.png"><strong>Superman</strong><a href="https://linuxfr.org">les joies du code</a>',
+                       'status' => Class_Article::STATUS_VALIDATED,
+                       'debut' => '2012-06-06 09:00:00',
+                       'fin' => '2012-06-06 09:00:00',
+                       'events_debut' => '2014-05-01 09:00:00',
+                       'events_fin' => '2014-06-03 09:00:00',
+                       'tags' => 'Jeunesse;Vieillesse;animation'
+                      ]),
+      ];
+
+    $dispatch=Class_Newsletter_Dispatch::newFrom($this->_letter);
+    $dispatch->collectRecipients();
+    $mail = Class_Newsletter_Template::newFrom($dispatch)
+      ->mailFor(Class_Newsletter_DispatchUser::findFirstBy(['user_id' => 120]));
+
+    $this->_html_content = quoted_printable_decode($mail->getBodyHtml(true));
+  }
+
+
+  public function tearDown(){
+    Class_Newsletter_TemplateHelper::setFileSystem(null);
+    Class_AdminVar::set('NEWSLETTER_INLINE_CSS',0);
+    Class_Newsletter::setTimeSource(null);
+    Class_UserGroup::setMemoryCleaner(null);
+    Zend_Registry::set('sql',null);
+    parent::tearDown();
+  }
+
+
+  /**
+   * @test
+   */
+  public function htmlContentShouldContainNewsletterContenu() {
+    $this->_xpath->assertXPathContentContains($this->_html_content,
+                                              '//p',
+                                              'Golgoth aperçu azimut 234.53');
+  }
+
+
+  /**
+   * @test
+   */
+  public function htmlContentShouldContainTwoH2Entries() {
+    $this->_xpath->assertXPathCount($this->_html_content,
+                                    '//h2',
+                                    3);
+  }
+
+
+  /** @test */
+  public function htmlContentShouldContainTwoVignettesSocialNetworkEntries() {
+    $this->_xpath->assertXPathCount($this->_html_content,
+                                    '//div[@class="vignette-reseaux-sociaux reseaux-sociaux"]',
+                                    3);
+  }
+
+
+  public function expectedHTMLTagWithContent(){
+    return [['//h2', 'joies du printemps'],
+            ['//h2', 'festival du film d\'animation'],
+            ['//img//@src', 'animage-1.png'],
+            ['//img//@src', 'animage-2.png'],
+            ['//dl[@class="article_info"]//dd[@class="event_start_date"]', 'dim. 01 juin'],
+            ['//dl[@class="article_info"]//dd[@class="event_end_date"]', 'mar. 03 juin'],
+            ['//dd[@class="event_tag"]', 'Jeunesse'],
+            ['//dd[@class="event_tag"]', 'animation'],
+    ];
+  }
+
+
+  /**
+   * @test
+   * @dataProvider expectedHTMLTagWithContent
+   */
+  public function htmlContentShouldContainExpectedContent($xpath, $expected_content) {
+    $this->_xpath->assertXPathContentContains($this->_html_content,
+                                              $xpath,
+                                              $expected_content,
+    $this->_html_content);
+  }
+
+
+  /** @test */
+  public function classEventTagShouldEmbedExpectedStyle() {
+    $this->_xpath->assertXPath($this->_html_content,
+                               '//dd[@class="event_tag"][@style="box-sizing: border-box; margin-bottom: .5rem; margin-left: 0;"]');
+  }
+
+  /** @test */
+  public function ddClassEventStartDateShouldEmbedExpectedStyle() {
+    $this->_xpath->assertXPath($this->_html_content,
+                               '//dd[@class="event_start_date"][@style="box-sizing: border-box; margin-bottom: .5rem; margin-left: 0;"]');
+  }
+}
diff --git a/tests/scenarios/Templates/TemplatesAgendaTest.php b/tests/scenarios/Templates/TemplatesAgendaTest.php
index 2a1821e693592a7f14dab838728e9360693d877d..3f1c9fb33412b07670a1bfab4b0eb20a7bd6b6e4 100644
--- a/tests/scenarios/Templates/TemplatesAgendaTest.php
+++ b/tests/scenarios/Templates/TemplatesAgendaTest.php
@@ -705,7 +705,7 @@ class TemplatesAgendaWallModeSelectedMonthIsCurrentMonthArticleWithoutEndDateTes
 
   /** @test */
   public function pageShouldContainsLinkToCmsArticleViewIdSevenWithoutContext() {
-    $this->assertXPath('//a[@href="/cms/articleview/id/7"]');
+    $this->assertXPath('//a[contains(@href,"/cms/articleview/id/7")]');
   }
 }
 
diff --git a/tests/scenarios/Templates/TemplatesArticlesTest.php b/tests/scenarios/Templates/TemplatesArticlesTest.php
index 467b941877e17ab96f4afa21a641c865c60956d0..228771be9c2761c312540c24c2bcbc5631af9cab 100644
--- a/tests/scenarios/Templates/TemplatesArticlesTest.php
+++ b/tests/scenarios/Templates/TemplatesArticlesTest.php
@@ -249,7 +249,7 @@ class TemplatesArticlesWidgetTest extends TemplatesArticlesWidgetTestCase {
 
   /** @test */
   public function articleLinkTitleShouldContainsEventDebut() {
-    $this->assertXPathContentContains('//a[@href="/cms/articleview/id/12"]//span[@class="sr-only"]',
+    $this->assertXPathContentContains('//a[contains(@href,"/cms/articleview/id/12")]//span[@class="sr-only"]',
                                       'Lire l\'article: Parlez-vous vraiment français ? 12/04/2020');
   }
 }
@@ -438,7 +438,7 @@ class TemplatesArticlesWithLocationViewTest extends TemplatesArticlesWithLocatio
 
   /** @test */
   public function metaOgForFacebookShouldBePresent() {
-    $this->assertXPath('//meta[@property="og:url"][contains(@content,"cms/articleview/id/7/id_profil/1")]');
+    $this->assertXPath('//meta[@property="og:url"][contains(@content,"cms/articleview/id/7")]');
   }
 
 
diff --git a/tests/scenarios/Templates/TemplatesNewslettersTest.php b/tests/scenarios/Templates/TemplatesNewslettersTest.php
index fc3af61a1c7dd6bf05fabe480f36686551d8bd51..a722b7a111fba56acd29eb62975fc297f62c738f 100644
--- a/tests/scenarios/Templates/TemplatesNewslettersTest.php
+++ b/tests/scenarios/Templates/TemplatesNewslettersTest.php
@@ -22,9 +22,6 @@
 
 class TemplatesNewslettersWidgetWithDescriptionLengthTest extends AbstractControllerTestCase {
 
-  protected $_storm_default_to_volatile = true;
-
-
   public function setUp() {
     parent::setUp();
     Class_AdminVar::set('TEMPLATING', 1);
@@ -78,7 +75,6 @@ class TemplatesNewslettersWidgetWithCatalogueTestCase
   extends AbstractControllerTestCase {
 
   protected
-    $_storm_default_to_volatile = true,
     $_nb_notices;
 
 
@@ -134,6 +130,98 @@ class TemplatesNewslettersWidgetWithCatalogueTestCase
     $this->assertXPathContentContains('//main//div[@class="card-title card_title card_title_Intonation_Library_View_Wrapper_Newsletter"]',
                                       'les nouveautés pour enfants');
   }
+
+
+  /** @test */
+  public function headerBoiteLettreDInformationShouldBeDisplayed() {
+    $this->assertXPathContentContains('//div[@class="widget-header card-header"][@role="heading"][@aria-level="2"]', "Boite lettres d'informations");
+  }
+}
+
+
+
+
+class TemplatesNewslettersWidgetNewsletterCarouselWithCustomCssTestCase
+  extends AbstractControllerTestCase {
+
+  protected
+    $_nb_notices;
+
+
+  public function setUp() {
+    parent::setUp();
+
+    $profile = $this->_buildTemplateProfil(['id' => 789789]);
+
+    $profile_patcher = (new Class_Template_ProfilePatcher(null))
+      ->setProfile($profile);
+
+    $profile_patcher
+      ->addWidget(Intonation_Library_Widget_Carousel_Newsletter_Definition::CODE,
+                  Class_Profil::DIV_MAIN,
+                  ['rendering' => 'card-description',
+                   'layout' => 'list',
+                   'size' => 2,
+                   'description_length' => 4]);
+
+    $this->fixture(Class_Catalogue::class,
+                   ['id' => 12,
+                    'libelle' => 'Les livres pour enfants',
+                    'annee_debut' => '2020',
+                    'section' => '4',
+                    'nouveaute' => 0,
+                    'thesaurus' => ';;',
+                    'indexer' => 0,
+                    'custom_form_id' => null,
+                    'custom_form_values' => '']);
+
+    $this->fixture(Class_Newsletter::class,
+                   ['id' => 1,
+                    'titre' => 'les nouveautés pour enfants',
+                    'contenu' => 'Voici les nouveautés : ',
+                    'mail_subject'=>'Enfants: nouveatés du mois de mars',
+                    'id_catalogue' => 12,
+                    'nb_notices' => $this->_nb_notices]);
+
+
+    $this->fixture(Class_Newsletter::class,
+                   ['id' => 2,
+                    'titre' => 'les nouveautés pour la jeunesse',
+                    'contenu' => 'Nouveautés jeunesse : ',
+                    'custom_css' => './skin/dinan/CSS/Newsletter.css',
+                    'render_with_widget' => '1',
+                    'mail_subject'=>'Jeunesse: nouveautés du mois de mars']);
+
+    $this->onLoaderOfModel(Class_Notice::class);
+
+    $this->dispatch('/');
+  }
+
+
+  /** @test */
+  public function newsletterWidgetShouldBePresent() {
+    $this->assertXPath('//div[@id="boite_1"][contains(@class, "boite newsletters")]');
+  }
+
+
+  /** @test */
+  public function newsletterNewsForChildrenShouldBeDisplay() {
+    $this->assertXPathContentContains('//main//div[@class="card-title card_title card_title_Intonation_Library_View_Wrapper_Newsletter"]',
+                                      'les nouveautés pour enfants');
+  }
+
+
+  /** @test */
+  public function newsletterNewsForYouthShouldBeDisplay() {
+    $this->assertXPathContentContains('//main//div[@class="card-title card_title card_title_Intonation_Library_View_Wrapper_Newsletter"]',
+                                      'les nouveautés pour la jeunesse');
+  }
+
+
+  /** @test */
+  public function headerBoiteLettreDInformationShouldBeDisplayed() {
+    $this->assertXPathContentContains('//div[@class="widget-header card-header"][@role="heading"][@aria-level="2"]', "Boite lettres d'informations");
+  }
 }
 
 
@@ -171,9 +259,6 @@ class TemplatesNewslettersWidgetWithCatalogueAndOneNbRecords extends TemplatesNe
 
 abstract class TemplatesNewslettersIndexWithWidgetTestCase extends AbstractControllerTestCase {
 
-  protected $_storm_default_to_volatile = true;
-
-
   public function setUp() {
     parent::setUp();
 
@@ -283,3 +368,50 @@ class TemplatesNewslettersIndexWithWidgetAndNoUserTest extends TemplatesNewslett
                                       'Cache de la boite newsletter.');
   }
 }
+
+
+
+
+class TemplatesNewslettersPreviewWithCustomCssTestCase
+  extends AbstractControllerTestCase {
+
+  protected
+    $_nb_notices;
+
+
+  public function setUp() {
+    parent::setUp();
+
+    $profile = $this->_buildTemplateProfil(['id' => 789789]);
+
+    $profile_patcher = (new Class_Template_ProfilePatcher(null))
+      ->setProfile($profile);
+
+    $this->fixture(Class_Article::class,
+                   ['id' => 12,
+                    'titre' => 'Les livres pour enfants',
+                    'description' => '<img src="/public/enfant.png"/> <p>Notre selection de livre pour enfants</p>',
+                    'contenu' => '<img src="/public/enfant.png"/> <p>Notre selection de livre pour enfants</p>',
+                    'debut' => '2023-01-01',
+                    'status' => Class_Article::STATUS_VALIDATED]);
+
+    $this->fixture(Class_Newsletter::class,
+                   ['id' => 1,
+                    'titre' => 'les nouveautés pour enfants',
+                    'contenu' => 'Voici les nouveautés : ',
+                    'mail_subject'=>'Enfants: nouveatés du mois de mars',
+                    'articles_ids' => '12',
+                    'custom_css' => './skin/dinan/CSS/Newsletter.css',
+                    'render_with_widget' => "1",
+                   ]);
+
+    $this->dispatch('/admin/newsletter/preview/id/1');
+  }
+
+
+  /** @test */
+  public function mainLinkForArticleShouldBeAbsolute() {
+    $this->assertXPathContentContains('//a[@class="card-link"]/@href',
+                                     Class_Article::find(12)->getAbsoluteUrl());
+  }
+}
diff --git a/tests/scenarios/Widgets/WidgetsTest.php b/tests/scenarios/Widgets/WidgetsTest.php
index c476c8022adeaeb286eb0b05dea2b7b250b2c113..d093bc5ee4437a27167814b71a7f97490b5fe8dd 100644
--- a/tests/scenarios/Widgets/WidgetsTest.php
+++ b/tests/scenarios/Widgets/WidgetsTest.php
@@ -676,17 +676,16 @@ class WidgetsCacheTest extends AbstractControllerTestCase {
 
 
   /** @test */
-  public function pageShouldContainsImgWithRelativeUrlTestPng() {
+  public function pageShouldContainsImgWithAbsoluteUrlTestPng() {
     $this->assertXPath('//body//div//img[@src="'
-                       . Class_Url::relative('/userfiles/test.png')
-                       . '"]',
-                       $this->_response->getBody());
+                       . Class_Url::absolute('/userfiles/test.png')
+                       . '"]');
   }
 
 
   /** @test */
   public function imageUrlShouldBeRelativeInCache() {
-    $this->assertContains('<img src="' . Class_Url::relative('/userfiles/test.png'),
+    $this->assertContains('<img src="' . Class_Url::absolute('/userfiles/test.png'),
                           Storm_Cache::getDefaultZendCache()
                           ->load('seed_170f2fbece44b9f4f4af3a51c18ed998'));
   }
diff --git a/tests/scenarios/Zotero/ZoteroTest.php b/tests/scenarios/Zotero/ZoteroTest.php
index fd1d1efe057d62443a416561c60d4a0628faf4a8..8204571b495ff45fc9321c9c2f511606bf9d3059 100644
--- a/tests/scenarios/Zotero/ZoteroTest.php
+++ b/tests/scenarios/Zotero/ZoteroTest.php
@@ -309,7 +309,7 @@ class ZoteroCmsArticleTest extends ZoteroTestCase {
             ['Z.blogTitle', 'My bokeh portal'],
             ['dc.creator', 'La bibliothécaire'],
             ['Z.date', '2022-04-26'],
-            ['Z.url', 'http://localhost'.BASE_URL.'/cms/articleview/id/8/id_profil/1']
+            ['Z.url', 'http://localhost'.BASE_URL.'/cms/articleview/id/8']
     ];
   }
 
@@ -319,7 +319,7 @@ class ZoteroCmsArticleTest extends ZoteroTestCase {
    * @dataProvider expectedMetasDatas
    */
   public function headMetasShouldContains($property, $content) {
-    $this->assertXPath(sprintf('//head/meta[@property="%s"][@content=\'%s\']', $property,$content) ,$this->_response->getbody());
+    $this->assertXPath(sprintf('//head/meta[@property="%s"][@content=\'%s\']', $property,$content));
   }
 }