diff --git a/adapters/AdapterInterface.php b/adapters/AdapterInterface.php
index 3a0dc85..c967bb2 100644
--- a/adapters/AdapterInterface.php
+++ b/adapters/AdapterInterface.php
@@ -119,9 +119,9 @@ interface AdapterInterface
      * @param array  $medias      : Array of medias to link to the MMS, [['http_url' => HTTP public url of the media et 'local_uri' => local uri to media file]]
      *
      * @return array : [
-     *               bool 'error' => false if no error, true else
-     *               ?string 'error_message' => null if no error, else error message
-     *               array 'uid' => Uid of the sms created on success
+     *               bool 'error' => false if no error, true else,
+     *               ?string 'error_message' => null if no error, else error message,
+     *               array 'uid' => Uid of the sms created on success,
      *               ]
      */
     public function send(string $destination, string $text, bool $flash = false, bool $mms = false, array $medias = []): array;
diff --git a/assets/css/style.css b/assets/css/style.css
index ea2f87d..204950f 100644
--- a/assets/css/style.css
+++ b/assets/css/style.css
@@ -311,7 +311,8 @@ footer img
 }
 
 /* SCHEDULEDS */
-.add-number-button
+.add-number-button,
+.add-phone-limit-button
 {
 	display: inline-block;
 	color: #DADFE1;
@@ -319,7 +320,8 @@ footer img
 	vertical-align: top;
 }
 
-.add-number-button:hover
+.add-number-button:hover,
+.add-phone-limit-button:hover
 {
 	color: #3498DB;
 	cursor: pointer;
@@ -373,7 +375,8 @@ footer img
     text-align: right;
 }
 
-.scheduleds-number-groupe
+.scheduleds-number-groupe,
+.phone-limits-group
 {
 	padding-top: 15px;
 	padding-bottom: 15px;
@@ -383,7 +386,8 @@ footer img
 	position: relative;
 }
 
-.scheduleds-number-groupe-remove
+.scheduleds-number-groupe-remove,
+.phone-limits-group-remove
 {
 	position: absolute;
 	top: 15px;
@@ -391,7 +395,8 @@ footer img
 	color: #888;
 }
 
-.scheduleds-number-groupe-remove:hover
+.scheduleds-number-groupe-remove:hover,
+.phone-limits-group-remove:hover
 {
 	color: #555;
 }
@@ -466,6 +471,16 @@ footer img
     color: #9b2420;
 }
 
+/* PREVIEW CONTACT */
+.preview-contact-name
+{
+    font-weight: bold;
+}
+
+.preview-contact-number
+{
+    font-style: italic;
+}
 
 /* PHONE */
 #adapter-data-container
diff --git a/composer.json b/composer.json
index 935f689..403cedf 100644
--- a/composer.json
+++ b/composer.json
@@ -14,8 +14,7 @@
         "symfony/yaml": "^5.0",
         "phpmailer/phpmailer": "^6.1",
         "xantios/mimey": ">=2.1",
-        "kreait/firebase-php": "^5.14"
-    },
-    "require-dev": {
+        "kreait/firebase-php": "^5.14",
+        "benmorel/gsm-charset-converter": "^0.3.0"
     }
 }
diff --git a/controllers/internals/Event.php b/controllers/internals/Event.php
index 29f76cb..003fc8d 100644
--- a/controllers/internals/Event.php
+++ b/controllers/internals/Event.php
@@ -73,21 +73,6 @@ namespace controllers\internals;
             return $this->get_model()->insert($event);
         }
 
-        /**
-         * Gets events for a type, since a date and eventually until a date (both included).
-         *
-         * @param int        $id_user : User id
-         * @param string     $type    : Event type we want
-         * @param \DateTime  $since   : Date to get events since
-         * @param ?\DateTime $until   (optional) : Date until wich we want events, if not specified no limit
-         *
-         * @return array
-         */
-        public function get_events_by_type_and_date_for_user(int $id_user, string $type, \DateTime $since, ?\DateTime $until = null)
-        {
-            $this->get_model()->get_events_by_type_and_date_for_user($id_user, $type, $since, $until);
-        }
-
         /**
          * Get the model for the Controller.
          */
diff --git a/controllers/internals/ExpressionProvider.php b/controllers/internals/ExpressionProvider.php
index 9d056ab..b26ff41 100644
--- a/controllers/internals/ExpressionProvider.php
+++ b/controllers/internals/ExpressionProvider.php
@@ -44,11 +44,6 @@ class ExpressionProvider implements ExpressionFunctionProviderInterface
             return sprintf('isset(%1$s) && is_a(%1$s, \'DateTime\') && %1$s->format(\'m-d\') == (new \\DateTime())->format(\'m-d\')', $birthdate);
         }, function ($arguments, DateTime $birthdate)
         {
-            if (!($birthdate ?? false))
-            {
-                return false;
-            }
-
             return $birthdate->format('m-d') == (new DateTime())->format('m-d');
         });
 
diff --git a/controllers/internals/Phone.php b/controllers/internals/Phone.php
index 0cf8354..9bdeac7 100644
--- a/controllers/internals/Phone.php
+++ b/controllers/internals/Phone.php
@@ -44,15 +44,15 @@ namespace controllers\internals;
         }
 
         /**
-         * Return a phone by his name.
+         * Return a list of phone limits
          *
-         * @param string $name : Phone name
+         * @param int $id_phone : Phone id
          *
          * @return array
          */
-        public function get_by_name(string $name)
+        public function get_limits(int $id_phone)
         {
-            return $this->get_model()->get_by_name($name);
+            return $this->get_model()->get_limits($id_phone);
         }
 
         /**
@@ -137,19 +137,46 @@ namespace controllers\internals;
          * @param string      $name         : The name of the phone
          * @param string      $adapter      : The adapter to use the phone
          * @param string json $adapter_data : A JSON string representing adapter's data (for example credentials for an api)
+         * @param int         $priority     : Priority with which to use phone to send SMS. Default 0.
+         * @param array       $limits       : An array of limits for this phone. Each limit must be an array with a key volume and a key startpoint
          *
          * @return bool|int : false on error, new id on success
          */
-        public function create(int $id_user, string $name, string $adapter, string $adapter_data)
+        public function create(int $id_user, string $name, string $adapter, string $adapter_data, int $priority = 0, array $limits = [])
         {
             $phone = [
                 'id_user' => $id_user,
                 'name' => $name,
+                'priority' => $priority,
                 'adapter' => $adapter,
                 'adapter_data' => $adapter_data,
             ];
 
-            return $this->get_model()->insert($phone);
+            //Use transaction to garanty atomicity
+            $this->bdd->beginTransaction();
+
+            $new_phone_id = $this->get_model()->insert($phone);
+            if (!$new_phone_id)
+            {
+                $this->bdd->rollBack();
+
+                return false;
+            }
+
+            foreach ($limits as $limit)
+            {
+                $limit_id = $this->get_model()->insert_phone_limit($new_phone_id, $limit['volume'], $limit['startpoint']);
+                
+                if (!$limit_id)
+                {
+                    $this->bdd->rollBack();
+
+                    return false;
+                }
+            }
+
+            $success = $this->bdd->commit();
+            return ($success ? $new_phone_id : false);
         }
 
         /**
@@ -159,20 +186,54 @@ namespace controllers\internals;
          * @param int    $id           : Phone id
          * @param string $name         : The name of the phone
          * @param string $adapter      : The adapter to use the phone
-         * @param array  $adapter_data : An array of the data of the adapter (for example credentials for an api)
+         * @param string json $adapter_data : A JSON string representing adapter's data (for example credentials for an api)
+         * @param int         $priority     : Priority with which to use phone to send SMS. Default 0.
+         * @param array  $limits       : An array of limits for this phone. Each limit must be an array with a key volume and a key startpoint
          *
          * @return bool : false on error, true on success
          */
-        public function update_for_user(int $id_user, int $id, string $name, string $adapter, array $adapter_data): bool
+        public function update_for_user(int $id_user, int $id, string $name, string $adapter, string $adapter_data, int $priority = 0, array $limits = []): bool
         {
             $phone = [
                 'id_user' => $id_user,
                 'name' => $name,
                 'adapter' => $adapter,
-                'adapter_data' => json_encode($adapter_data),
+                'adapter_data' => $adapter_data,
+                'priority' => $priority,
             ];
 
-            return (bool) $this->get_model()->update_for_user($id_user, $id, $phone);
+            //Use transaction to garanty atomicity
+            $this->bdd->beginTransaction();
+            
+            $nb_delete = $this->get_model()->delete_phone_limits($id);
+
+            foreach ($limits as $limit)
+            {
+                $limit_id = $this->get_model()->insert_phone_limit($id, $limit['volume'], $limit['startpoint']);
+                
+                if (!$limit_id)
+                {
+                    $this->bdd->rollBack();
+
+                    return false;
+                }
+            }
+
+            $nb_update = $this->get_model()->update_for_user($id_user, $id, $phone);
+            
+            $success = $this->bdd->commit();
+
+            if (!$success)
+            {
+                return false;
+            }
+
+            if ($nb_update == 0 && count($limits) == 0)
+            {
+                return false;
+            }
+
+            return true;
         }
 
         /**
diff --git a/controllers/internals/Scheduled.php b/controllers/internals/Scheduled.php
index 25ce51e..4f0c3f7 100644
--- a/controllers/internals/Scheduled.php
+++ b/controllers/internals/Scheduled.php
@@ -274,236 +274,6 @@ use Monolog\Logger;
             return $this->get_model()->gets_after_date_for_number_and_user($id_user, $date, $number);
         }
 
-        /**
-         * Get all messages to send and the number to use to send theme.
-         *
-         * @return array : List of smss to send at this time per scheduled id ['1' => [['id_scheduled', 'text', 'id_phone', 'destination', 'flash', 'mms', 'medias'], ...], ...]
-         */
-        public function get_smss_to_send()
-        {
-            $smss_to_send_per_scheduled = [];
-
-            $internal_templating = new \controllers\internals\Templating();
-            $internal_setting = new \controllers\internals\Setting($this->bdd);
-            $internal_group = new \controllers\internals\Group($this->bdd);
-            $internal_conditional_group = new \controllers\internals\ConditionalGroup($this->bdd);
-            $internal_phone = new \controllers\internals\Phone($this->bdd);
-            $internal_smsstop = new \controllers\internals\SmsStop($this->bdd);
-
-            $users_smsstops = [];
-            $users_settings = [];
-            $users_phones = [];
-            $users_mms_phones = [];
-
-            $now = new \DateTime();
-            $now = $now->format('Y-m-d H:i:s');
-            $scheduleds = $this->get_model()->gets_before_date($now);
-            foreach ($scheduleds as $scheduled)
-            {
-                $smss_to_send_per_scheduled[$scheduled['id']] = [];
-
-                if (!isset($users_settings[$scheduled['id_user']]))
-                {
-                    $users_settings[$scheduled['id_user']] = [];
-
-                    $settings = $internal_setting->gets_for_user($scheduled['id_user']);
-                    foreach ($settings as $name => $value)
-                    {
-                        $users_settings[$scheduled['id_user']][$name] = $value;
-                    }
-                }
-
-                if (!isset($users_smsstops[$scheduled['id_user']]) && $users_settings[$scheduled['id_user']]['smsstop'])
-                {
-                    $users_smsstops[$scheduled['id_user']] = [];
-
-                    $smsstops = $internal_smsstop->gets_for_user($scheduled['id_user']);
-                    foreach ($smsstops as $smsstop)
-                    {
-                        $users_smsstops[$scheduled['id_user']][] = $smsstop['number'];
-                    }
-                }
-
-                if (!isset($users_phones[$scheduled['id_user']]))
-                {
-                    $phones = $internal_phone->gets_for_user($scheduled['id_user']);
-                    $mms_phones = $internal_phone->gets_phone_supporting_mms_for_user($scheduled['id_user'], $internal_phone::MMS_SENDING);
-                    $users_phones[$scheduled['id_user']] = $phones ?: [];
-                    $users_mms_phones[$scheduled['id_user']] = $mms_phones ?: [];
-                }
-
-                //Add medias to mms
-                $scheduled['medias'] = [];
-                if ($scheduled['mms'])
-                {
-                    $internal_media = new Media($this->bdd);
-                    $scheduled['medias'] = $internal_media->gets_for_scheduled($scheduled['id']);
-                }
-
-                $phone_to_use = null;
-                foreach ($users_phones[$scheduled['id_user']] as $phone)
-                {
-                    if ($phone['id'] !== $scheduled['id_phone'])
-                    {
-                        continue;
-                    }
-
-                    $phone_to_use = $phone;
-                }
-
-                $messages = [];
-
-                //Add messages for numbers
-                $numbers = $this->get_numbers($scheduled['id']);
-                foreach ($numbers as $number)
-                {
-                    if (null === $phone_to_use)
-                    {
-                        if ($scheduled['mms'] && count($users_mms_phones))
-                        {
-                            $rnd_key = array_rand($users_mms_phones[$scheduled['id_user']]);
-                            $random_phone = $users_mms_phones[$scheduled['id_user']][$rnd_key];
-                        }
-                        else
-                        {
-                            $rnd_key = array_rand($users_phones[$scheduled['id_user']]);
-                            $random_phone = $users_phones[$scheduled['id_user']][$rnd_key];
-                        }
-                    }
-
-                    $message = [
-                        'id_user' => $scheduled['id_user'],
-                        'id_scheduled' => $scheduled['id'],
-                        'id_phone' => $phone_to_use['id'] ?? $random_phone['id'],
-                        'destination' => $number['number'],
-                        'flash' => $scheduled['flash'],
-                        'mms' => $scheduled['mms'],
-                        'medias' => $scheduled['medias'],
-                    ];
-
-                    if ((int) ($users_settings[$scheduled['id_user']]['templating'] ?? false))
-                    {
-                        $number['data'] = json_decode($number['data'] ?? '[]', true);
-
-                        $metas = ['number' => $number['number']];
-                        $data = ['contact' => $number['data'], 'contact_metas' => $metas];
-
-                        $render = $internal_templating->render($scheduled['text'], $data);
-
-                        if (!$render['success'])
-                        {
-                            continue;
-                        }
-
-                        $message['text'] = $render['result'];
-                    }
-                    else
-                    {
-                        $message['text'] = $scheduled['text'];
-                    }
-
-                    $messages[] = $message;
-                }
-
-                //Add messages for contacts
-                $contacts = $this->get_contacts($scheduled['id']);
-
-                $groups = $this->get_groups($scheduled['id']);
-                foreach ($groups as $group)
-                {
-                    $contacts_to_add = $internal_group->get_contacts($group['id']);
-                    $contacts = array_merge($contacts, $contacts_to_add);
-                }
-
-                $conditional_groups = $this->get_conditional_groups($scheduled['id']);
-                foreach ($conditional_groups as $conditional_group)
-                {
-                    $contacts_to_add = $internal_conditional_group->get_contacts_for_condition_and_user($scheduled['id_user'], $conditional_group['condition']);
-                    $contacts = array_merge($contacts, $contacts_to_add);
-                }
-
-                $added_contacts = [];
-                foreach ($contacts as $contact)
-                {
-                    if ($added_contacts[$contact['id']] ?? false)
-                    {
-                        continue;
-                    }
-
-                    $added_contacts[$contact['id']] = true;
-
-                    if (null === $phone_to_use)
-                    {
-                        if ($scheduled['mms'] && count($users_mms_phones))
-                        {
-                            $rnd_key = array_rand($users_mms_phones[$scheduled['id_user']]);
-                            $random_phone = $users_mms_phones[$scheduled['id_user']][$rnd_key];
-                        }
-                        else
-                        {
-                            $rnd_key = array_rand($users_phones[$scheduled['id_user']]);
-                            $random_phone = $users_phones[$scheduled['id_user']][$rnd_key];
-                        }
-                    }
-
-                    $message = [
-                        'id_user' => $scheduled['id_user'],
-                        'id_scheduled' => $scheduled['id'],
-                        'id_phone' => $phone_to_use['id'] ?? $random_phone['id'],
-                        'destination' => $contact['number'],
-                        'flash' => $scheduled['flash'],
-                        'mms' => $scheduled['mms'],
-                        'medias' => $scheduled['medias'],
-                    ];
-
-                    if ((int) ($users_settings[$scheduled['id_user']]['templating'] ?? false))
-                    {
-                        $contact['data'] = json_decode($contact['data'], true);
-
-                        //Add metas of contact by adding contact without data
-                        $metas = $contact;
-                        unset($metas['data'], $metas['id_user']);
-
-                        $data = ['contact' => $contact['data'], 'contact_metas' => $metas];
-
-                        $render = $internal_templating->render($scheduled['text'], $data);
-
-                        if (!$render['success'])
-                        {
-                            continue;
-                        }
-
-                        $message['text'] = $render['result'];
-                    }
-                    else
-                    {
-                        $message['text'] = $scheduled['text'];
-                    }
-
-                    $messages[] = $message;
-                }
-
-                foreach ($messages as $message)
-                {
-                    //Remove empty messages
-                    if ('' === trim($message['text']) && !$message['medias'])
-                    {
-                        continue;
-                    }
-
-                    //Remove messages to smsstops numbers
-                    if (($users_smsstops[$scheduled['id_user']] ?? false) && in_array($message['destination'], $users_smsstops[$scheduled['id_user']]))
-                    {
-                        continue;
-                    }
-
-                    $smss_to_send_per_scheduled[$scheduled['id']][] = $message;
-                }
-            }
-
-            return $smss_to_send_per_scheduled;
-        }
-
         /**
          * Parse a CSV file of numbers, potentially associated with datas.
          *
@@ -627,4 +397,292 @@ use Monolog\Logger;
 
             return $this->model;
         }
+
+
+        /**
+         * Get all messages to send and the number to use to send theme.
+         *
+         * @return array : List of smss to send at this time per scheduled id ['1' => [['id_scheduled', 'text', 'id_phone', 'destination', 'flash', 'mms', 'medias'], ...], ...]
+         */
+        public function get_smss_to_send()
+        {
+            $sms_per_scheduled = [];
+
+            $internal_templating = new \controllers\internals\Templating();
+            $internal_setting = new \controllers\internals\Setting($this->bdd);
+            $internal_group = new \controllers\internals\Group($this->bdd);
+            $internal_conditional_group = new \controllers\internals\ConditionalGroup($this->bdd);
+            $internal_phone = new \controllers\internals\Phone($this->bdd);
+            $internal_smsstop = new \controllers\internals\SmsStop($this->bdd);
+            $internal_sended = new \controllers\internals\Sended($this->bdd);
+
+            $users_smsstops = [];
+            $users_settings = [];
+            $users_phones = [];
+            $users_mms_phones = [];
+
+            $now = new \DateTime();
+            $now = $now->format('Y-m-d H:i:s');
+            $scheduleds = $this->get_model()->gets_before_date($now);
+            foreach ($scheduleds as $scheduled)
+            {
+                $id_scheduled = $scheduled['id'];
+                $id_user = $scheduled['id_user'];
+
+                $sms_per_scheduled[$id_scheduled] = [];
+
+                // Forge cache of data about users, sms stops, phones, etc.
+                if (!isset($users_settings[$id_user]))
+                {
+                    $users_settings[$id_user] = [];
+
+                    $settings = $internal_setting->gets_for_user($id_user);
+                    foreach ($settings as $name => $value)
+                    {
+                        $users_settings[$id_user][$name] = $value;
+                    }
+                }
+
+                if (!isset($users_smsstops[$id_user]) && $users_settings[$id_user]['smsstop'])
+                {
+                    $users_smsstops[$id_user] = [];
+
+                    $smsstops = $internal_smsstop->gets_for_user($id_user);
+                    foreach ($smsstops as $smsstop)
+                    {
+                        $users_smsstops[$id_user][] = $smsstop['number'];
+                    }
+                }
+
+                if (!isset($users_phones[$id_user]))
+                {
+                    $users_phones[$id_user] = [];
+                    $users_mms_phones[$id_user] = [];
+
+                    $phones = $internal_phone->gets_for_user($id_user);
+                    foreach ($phones as &$phone)
+                    {
+                        $limits = $internal_phone->get_limits($phone['id']);
+
+                        $remaining_volume = PHP_INT_MAX;
+                        foreach ($limits as $limit)
+                        {
+                            $startpoint = new \DateTime($limit['startpoint']);
+                            $consumed = $internal_sended->count_since_for_phone_and_user($id_user, $phone['id'], $startpoint);
+                            $remaining_volume = min(($limit['volume'] - $consumed), $remaining_volume);
+                        }
+
+                        $phone['remaining_volume'] = $remaining_volume;
+                        $users_phones[$id_user][$phone['id']] = $phone;
+                    }
+
+                    $mms_phones = $internal_phone->gets_phone_supporting_mms_for_user($id_user, $internal_phone::MMS_SENDING);
+                    foreach ($mms_phones as &$mms_phone)
+                    {
+                        $limits = $internal_phone->get_limits($mms_phone['id']);
+
+                        $remaining_volume = PHP_INT_MAX;
+                        foreach ($limits as $limit)
+                        {
+                            $startpoint = new \DateTime($limit['startpoint']);
+                            $consumed = $internal_sended->count_since_for_phone_and_user($id_user, $mms_phone['id'], $startpoint);
+                            $remaining_volume = min(($limit['volume'] - $consumed), $remaining_volume);
+                        }
+
+                        $mms_phone['remaining_volume'] = $remaining_volume;
+                        $users_mms_phones[$id_user][$mms_phone['id']] = $mms_phone;
+                    }
+                }
+
+
+                //Add medias to mms
+                $scheduled['medias'] = [];
+                if ($scheduled['mms'])
+                {
+                    $internal_media = new Media($this->bdd);
+                    $scheduled['medias'] = $internal_media->gets_for_scheduled($id_scheduled);
+                }
+
+                $phone_to_use = null;
+                if ($scheduled['id_phone'])
+                {
+                    $phone_to_use = $users_phones[$id_user][$scheduled['id_phone']] ?? null;
+                }
+
+
+                // We turn all contacts, groups and conditional groups into just contacts
+                $contacts = $this->get_contacts($id_scheduled);
+
+                $groups = $this->get_groups($id_scheduled);
+                foreach ($groups as $group)
+                {
+                    $contacts_to_add = $internal_group->get_contacts($group['id']);
+                    $contacts = array_merge($contacts, $contacts_to_add);
+                }
+
+                $conditional_groups = $this->get_conditional_groups($id_scheduled);
+                foreach ($conditional_groups as $conditional_group)
+                {
+                    $contacts_to_add = $internal_conditional_group->get_contacts_for_condition_and_user($id_user, $conditional_group['condition']);
+                    $contacts = array_merge($contacts, $contacts_to_add);
+                }
+
+
+                // We turn all numbers and contacts into simple targets with number, data and meta so we can forge all messages from onlye one data source
+                $targets = [];
+                
+                $numbers = $this->get_numbers($id_scheduled);
+                foreach ($numbers as $number)
+                {
+                    $metas = ['number' => $number['number']];
+                    $targets[] = [
+                        'number' => $number['number'],
+                        'data' => $number['data'],
+                        'metas' => $metas,
+                    ];
+                }
+
+                foreach ($contacts as $contact)
+                {
+                    $metas = $contact;
+                    unset($metas['data'], $metas['id_user']);
+
+                    $targets[] = [
+                        'number' => $contact['number'],
+                        'data' => $contact['data'],
+                        'metas' => $metas,
+                    ];
+                }
+
+                
+                // Pass on all targets to deduplicate destinations, remove number in sms stops, etc.
+                $used_destinations = [];
+                foreach ($targets as $key => $target)
+                {
+                    if (in_array($target['number'], $used_destinations))
+                    {
+                        unset($targets[$key]);
+                        continue;
+                    }
+
+                    //Remove messages to smsstops numbers
+                    if (($users_smsstops[$id_user] ?? false) && in_array($target['number'], $users_smsstops[$id_user]))
+                    {
+                        continue;
+                    }
+
+                    $used_destinations[] = $target['number'];
+                }
+                
+                
+                // Finally, we forge all messages and select phone to use
+                foreach ($targets as $target)
+                {
+                    // Forge message if templating enable
+                    $text = $scheduled['text'];
+                    if ((int) ($users_settings[$id_user]['templating'] ?? false)) // Cast to int because it is more reliable than bool on strings
+                    {
+                        $target['data'] = json_decode($target['data'], true);
+                        $data = ['contact' => $target['data'], 'contact_metas' => $target['metas']];
+
+                        $render = $internal_templating->render($scheduled['text'], $data);
+
+                        if (!$render['success'])
+                        {
+                            continue;
+                        }
+
+                        $text = $render['result'];
+                    }
+
+                    // Ignore empty messages
+                    if ('' === trim($text) && !$scheduled['medias'])
+                    {
+                        continue;
+                    }
+
+                    // If we must force GSM 7 alphabet
+                    if ((int) ($users_settings[$id_user]['force_gsm_alphabet'] ?? false))
+                    {
+                        $text = Tool::convert_to_gsm0338($text);
+                    }
+
+                    /*
+                        Choose phone if no phone defined for message
+                        Phones are choosen using type, priority and remaining volume :
+                            1 - If sms is a mms, try to use mms phone if any available. If mms phone available use mms phone, else use default.
+                            2 - In group of phones, keep only phones with remaining volume. If no phones with remaining volume, use all phones instead.
+                            3 - Groupe keeped phones by priority get group with biggest priority.
+                            4 - Get a random phone in this group.
+                            5 - If their is no phone matching, keep phone at null so sender will directly mark it as failed
+                    */
+                    $random_phone = null;
+                    if (null === $phone_to_use)
+                    {
+                        $phones_subset = $users_phones[$id_user];
+                        if ($scheduled['mms'])
+                        {
+                            $phones_subset = $users_mms_phones[$id_user] ?: $phones_subset;
+                        }
+
+                        $remaining_volume_phones = array_filter($phones_subset, function ($phone) {
+                            return $phone['remaining_volume'] > 0;
+                        });
+                        $phones_subset = $remaining_volume_phones ?: $phones_subset;
+
+                        $max_priority_phones = [];
+                        $max_priority = PHP_INT_MIN;
+                        foreach ($phones_subset as $phone)
+                        {
+                            if ($phone['priority'] < $max_priority)
+                            {
+                                continue;
+                            }
+                            elseif ($phone['priority'] == $max_priority)
+                            {
+                                $max_priority_phones[] = $phone;
+                            }
+                            elseif ($phone['priority'] > $max_priority)
+                            {
+                                $max_priority_phones = [$phone];
+                                $max_priority = $phone['priority'];
+                            }
+                        }
+
+                        $phones_subset = $max_priority_phones;
+                        if ($phones_subset)
+                        {
+                            $random_phone = $phones_subset[array_rand($phones_subset)];
+                        }
+                    }
+
+                    // This should only happen if the user try to send a message without any phone in his account, then we simply ignore.
+                    if (!$random_phone && !$phone_to_use)
+                    {
+                        continue;
+                    }
+                    
+                    $id_phone = $phone_to_use['id'] ?? $random_phone['id'];
+                    $sms_per_scheduled[$id_scheduled][] = [
+                        'id_user' => $id_user,
+                        'id_scheduled' => $id_scheduled,
+                        'id_phone' => $id_phone,
+                        'destination' => $target['number'],
+                        'flash' => $scheduled['flash'],
+                        'mms' => $scheduled['mms'],
+                        'medias' => $scheduled['medias'],
+                        'text' => $text,
+                    ];
+
+                    // Consume one sms from remaining volume of phone, dont forget to do the same for the entry in mms phones
+                    $users_phones[$id_user][$id_phone]['remaining_volume'] --;
+                    if ($users_mms_phones[$id_user][$id_phone] ?? false)
+                    {
+                        $users_mms_phones[$id_user][$id_phone] --;
+                    }
+                }
+            }
+
+            return $sms_per_scheduled;
+        }
     }
diff --git a/controllers/internals/Sended.php b/controllers/internals/Sended.php
index 9cce107..6a9276c 100644
--- a/controllers/internals/Sended.php
+++ b/controllers/internals/Sended.php
@@ -179,6 +179,20 @@ namespace controllers\internals;
             return $this->get_model()->get_by_uid_and_adapter_for_user($id_user, $uid, $adapter);
         }
 
+        /**
+         * Get number of sended SMS since a date for a phone
+         * 
+         * @param int $id_user : User id
+         * @param int $id_phone : Phone id we want the number of sended message for
+         * @param \DateTime $since : Date since which we want sended number
+         * 
+         * @return int
+         */
+        public function count_since_for_phone_and_user(int $id_user, int $id_phone, \DateTime $since): int
+        {
+            return $this->get_model()->count_since_for_phone_and_user($id_user, $id_phone, $since);
+        }
+
         /**
          * Get number of sended SMS for every date since a date for a specific user.
          *
@@ -239,17 +253,6 @@ namespace controllers\internals;
                 'error_message' => null,
             ];
 
-            //If we reached our max quota, do not send the message
-            $internal_quota = new Quota($this->bdd);
-            $nb_credits = $internal_quota::compute_credits_for_message($text); //Calculate how much credit the message require
-            if (!$internal_quota->has_enough_credit($id_user, $nb_credits))
-            {
-                $return['error'] = false;
-                $return['error_message'] = 'Not enough credit to send message.';
-
-                return $return;
-            }
-
             $at = (new \DateTime())->format('Y-m-d H:i:s');
             $media_uris = [];
             foreach ($medias as $media)
@@ -272,38 +275,56 @@ namespace controllers\internals;
                 $text .= "\n" . join(' - ', $media_urls);
             }
 
-            $response = $adapter->send($destination, $text, $flash, $mms, $media_uris);
-
-            if ($response['error'])
+            //If we reached our max quota, do not send the message
+            $internal_quota = new Quota($this->bdd);
+            $nb_credits = $internal_quota::compute_credits_for_message($text); //Calculate how much credit the message require
+            if (!$internal_quota->has_enough_credit($id_user, $nb_credits))
             {
                 $return['error'] = true;
-                $return['error_message'] = $response['error_message'];
-                $status = \models\Sended::STATUS_FAILED;
-                $sended_id = $this->create($id_user, $id_phone, $at, $text, $destination, $response['uid'] ?? uniqid(), $adapter->meta_classname(), $flash, $mms, $medias, $originating_scheduled, $status);
-
-                $sended = [
-                    'id' => $sended_id,
-                    'at' => $at,
-                    'status' => $status,
-                    'text' => $text,
-                    'destination' => $destination,
-                    'origin' => $id_phone,
-                    'mms' => $mms,
-                    'medias' => $medias,
-                    'originating_scheduled' => $originating_scheduled,
-                ];
-
-                $internal_webhook = new Webhook($this->bdd);
-                $internal_webhook->trigger($id_user, \models\Webhook::TYPE_SEND_SMS, $sended);
-
-                return $return;
+                $return['error_message'] = 'Not enough credit to send message.';
             }
 
-            $internal_quota->consume_credit($id_user, $nb_credits);
+            //If we reached limit for this phone, do not send the message
+            $internal_phone = new Phone($this->bdd);
+            $internal_sended = new Sended($this->bdd);
+            $limits = $internal_phone->get_limits($id_phone);
 
-            $sended_id = $this->create($id_user, $id_phone, $at, $text, $destination, $response['uid'] ?? uniqid(), $adapter->meta_classname(), $flash, $mms, $medias, $originating_scheduled, $status);
+            $remaining_volume = PHP_INT_MAX;
+            foreach ($limits as $limit)
+            {
+                $startpoint = new \DateTime($limit['startpoint']);
+                $consumed = $internal_sended->count_since_for_phone_and_user($id_user, $id_phone, $startpoint);
+                $remaining_volume = min(($limit['volume'] - $consumed), $remaining_volume);
+            }
 
-            $sended = [
+            if ($remaining_volume < 1)
+            {
+                $return['error'] = true;
+                $return['error_message'] = 'Phone send limit have been reached.';
+            }
+
+            $uid = uniqid();
+            if (!$return['error'])
+            {
+                $response = $adapter->send($destination, $text, $flash, $mms, $media_uris);
+                $uid = $response['uid'] ?? $uid;
+
+                if ($response['error'])
+                {
+                    $return['error'] = true;
+                    $return['error_message'] = $response['error_message'];
+                }
+                else // If send with success, consume credit
+                {
+                    $internal_quota->consume_credit($id_user, $nb_credits);
+                }
+            }
+
+            // If we fail to send or not, we will always save message as sended, only the status will change.
+            $status = $return['error'] ? \models\Sended::STATUS_FAILED : \models\Sended::STATUS_UNKNOWN;
+            $sended_id = $this->create($id_user, $id_phone, $at, $text, $destination, $uid, $adapter->meta_classname(), $flash, $mms, $medias, $originating_scheduled, $status);
+            
+            $webhook_body = [
                 'id' => $sended_id,
                 'at' => $at,
                 'status' => $status,
@@ -316,7 +337,7 @@ namespace controllers\internals;
             ];
 
             $internal_webhook = new Webhook($this->bdd);
-            $internal_webhook->trigger($id_user, \models\Webhook::TYPE_SEND_SMS, $sended);
+            $internal_webhook->trigger($id_user, \models\Webhook::TYPE_SEND_SMS, $webhook_body);
 
             return $return;
         }
diff --git a/controllers/internals/Tool.php b/controllers/internals/Tool.php
index e6b8994..a09fab6 100644
--- a/controllers/internals/Tool.php
+++ b/controllers/internals/Tool.php
@@ -11,6 +11,8 @@
 
 namespace controllers\internals;
 
+use BenMorel\GsmCharsetConverter\Converter;
+
     /**
      * Some tools frequently used.
      * Not a standard controller as it's not linked to a model in any way.
@@ -165,6 +167,24 @@ namespace controllers\internals;
             return $objectDate && $objectDate->format($format) === $date;
         }
 
+        /**
+         * Check if a relative format date (see https://www.php.net/manual/en/datetime.formats.relative.php) is valid.
+         *
+         * @param string $date   : Relative date
+         *
+         * @return bool : True if valid, false else
+         */
+        public static function validate_relative_date($date)
+        {
+            try {
+                $d = new \DateTime($date);
+            } catch (\Throwable $th) {
+                return false;
+            }
+
+            return true;
+        }
+
         /**
          * Check if a sting represent a valid PHP period for creating an interval.
          *
@@ -394,4 +414,17 @@ namespace controllers\internals;
 
             return "{$scheme}{$user}{$pass}{$host}{$port}{$path}{$query}{$fragment}";
         }
+
+
+        /**
+         * Transform an UTF-8 string into a valid GSM 7 string (GSM 03.38), remplacing invalid chars with best equivalent whenever possible
+         * 
+         * @param string $text : Input text to convert into gsm string
+         * @return string : An UTF-8 string with GSM alphabet only
+         */
+        public static function convert_to_gsm0338(string $text): string
+        {
+            $converter = new Converter();
+            return $converter->cleanUpUtf8String($text, true, '?');
+        }
     }
diff --git a/controllers/internals/Webhook.php b/controllers/internals/Webhook.php
index bb2c3bd..6a2e8cf 100644
--- a/controllers/internals/Webhook.php
+++ b/controllers/internals/Webhook.php
@@ -137,10 +137,10 @@ class Webhook extends StandardController
 
             $error_code = null;
             $queue = msg_get_queue(QUEUE_ID_WEBHOOK);
-            $success = msg_send($queue, QUEUE_TYPE_WEBHOOK, $message, true, true, $error_code);
-
-            return (bool) $success;
+            msg_send($queue, QUEUE_TYPE_WEBHOOK, $message, true, true, $error_code);
         }
+
+        return true;
     }
 
     /**
diff --git a/controllers/publics/Api.php b/controllers/publics/Api.php
index 92fb2ea..7ee0d36 100644
--- a/controllers/publics/Api.php
+++ b/controllers/publics/Api.php
@@ -506,6 +506,8 @@ namespace controllers\publics;
          * @param string $_POST['name']         : Phone name
          * @param string $_POST['adapter']      : Phone adapter
          * @param array  $_POST['adapter_data'] : Phone adapter data
+         * @param int    $priority              : Priority with which to use phone to send SMS. Default 0.
+         * @param ?array $_POST['limits']       : Array of limits in number of SMS for a period to be applied to this phone.
          *
          * @return int : id phone the new phone on success
          */
@@ -516,6 +518,10 @@ namespace controllers\publics;
             $name = $_POST['name'] ?? false;
             $adapter = $_POST['adapter'] ?? false;
             $adapter_data = !empty($_POST['adapter_data']) ? $_POST['adapter_data'] : [];
+            $priority = $_POST['priority'] ?? 0;
+            $priority = max(((int) $priority), 0);
+            $limits = $_POST['limits'] ?? [];
+            $limits = is_array($limits) ? $limits : [$limits];
 
             if (!$name)
             {
@@ -535,7 +541,7 @@ namespace controllers\publics;
                 return $this->json($return);
             }
 
-            $name_exist = $this->internal_phone->get_by_name($name);
+            $name_exist = $this->internal_phone->get_by_name_and_user($this->user['id'], $name);
             if ($name_exist)
             {
                 $return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
@@ -545,6 +551,36 @@ namespace controllers\publics;
                 return $this->json($return);
             }
 
+            if ($limits)
+            {
+                foreach ($limits as $key => $limit)
+                {
+                    if (!is_array($limit))
+                    {
+                        unset($limits[$key]);
+                        continue;
+                    }
+                    
+                    $startpoint = $limit['startpoint'] ?? false;
+                    $volume = $limit['volume'] ?? false;
+
+                    if (!$startpoint || !$volume)
+                    {
+                        unset($limits[$key]);
+                        continue;
+                    }
+
+                    $volume = (int) $volume;
+                    $limits[$key]['volume'] = max($volume, 1);
+
+                    if (!\controllers\internals\Tool::validate_relative_date($startpoint))
+                    {
+                        unset($limits[$key]);
+                        continue;
+                    }
+                }
+            }
+
             $adapters = $this->internal_adapter->list_adapters();
             $find_adapter = false;
             foreach ($adapters as $metas)
@@ -627,7 +663,7 @@ namespace controllers\publics;
                 return $this->json($return);
             }
 
-            $phone_id = $this->internal_phone->create($this->user['id'], $name, $adapter, $adapter_data);
+            $phone_id = $this->internal_phone->create($this->user['id'], $name, $adapter, $adapter_data, $priority, $limits);
             if (false === $phone_id)
             {
                 $return['error'] = self::ERROR_CODES['CANNOT_CREATE'];
@@ -650,6 +686,7 @@ namespace controllers\publics;
          * @param string (optionnal) $_POST['name']         : New phone name
          * @param string (optionnal) $_POST['adapter']      : New phone adapter
          * @param array  (optionnal) $_POST['adapter_data'] : New phone adapter data
+         * @param int         $priority     : Priority with which to use phone to send SMS. Default 0.
          *
          * @return int : id phone the new phone on success
          */
@@ -667,10 +704,16 @@ namespace controllers\publics;
                 return $this->json($return);
             }
 
+            $limits = $this->internal_phone->get_limits(($phone['id']));
+
             $name = $_POST['name'] ?? $phone['name'];
+            $priority = $_POST['priority'] ?? $phone['priority'];
+            $priority = max(((int) $priority), 0);
             $adapter = $_POST['adapter'] ?? $phone['adapter'];
             $adapter_data = !empty($_POST['adapter_data']) ? $_POST['adapter_data'] : json_decode($phone['adapter_data']);
             $adapter_data = is_array($adapter_data) ? $adapter_data : [$adapter_data];
+            $limits = $_POST['limits'] ?? $limits;
+            $limits = is_array($limits) ? $limits : [$limits];
 
 
             if (!$name && !$adapter && !$adapter_data)
@@ -683,7 +726,7 @@ namespace controllers\publics;
             }
 
 
-            $phone_with_same_name = $this->internal_phone->get_by_name($name);
+            $phone_with_same_name = $this->internal_phone->get_by_name_and_user($this->user['id'], $name);
             if ($phone_with_same_name && $phone_with_same_name['id'] != $phone['id'])
             {
                 $return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
@@ -693,6 +736,36 @@ namespace controllers\publics;
                 return $this->json($return);
             }
 
+            if ($limits)
+            {
+                foreach ($limits as $key => $limit)
+                {
+                    if (!is_array($limit))
+                    {
+                        unset($limits[$key]);
+                        continue;
+                    }
+                    
+                    $startpoint = $limit['startpoint'] ?? false;
+                    $volume = $limit['volume'] ?? false;
+
+                    if (!$startpoint || !$volume)
+                    {
+                        unset($limits[$key]);
+                        continue;
+                    }
+
+                    $volume = (int) $volume;
+                    $limits[$key]['volume'] = max($volume, 1);
+
+                    if (!\controllers\internals\Tool::validate_relative_date($startpoint))
+                    {
+                        unset($limits[$key]);
+                        continue;
+                    }
+                }
+            }
+
             $adapters = $this->internal_adapter->list_adapters();
             $find_adapter = false;
             foreach ($adapters as $metas)
@@ -775,7 +848,7 @@ namespace controllers\publics;
                 return $this->json($return);
             }
 
-            $success = $this->internal_phone->update_for_user($this->user['id'], $phone['id'], $name, $adapter, $adapter_data);
+            $success = $this->internal_phone->update_for_user($this->user['id'], $phone['id'], $name, $adapter, $adapter_data_json, $priority, $limits);
             if (!$success)
             {
                 $return['error'] = self::ERROR_CODES['CANNOT_UPDATE'];
diff --git a/controllers/publics/ConditionalGroup.php b/controllers/publics/ConditionalGroup.php
index 2a1aad8..8f1f3ea 100644
--- a/controllers/publics/ConditionalGroup.php
+++ b/controllers/publics/ConditionalGroup.php
@@ -185,6 +185,45 @@ namespace controllers\publics;
             return $this->redirect(\descartes\Router::url('ConditionalGroup', 'list'));
         }
 
+        /**
+         * Return contacts of a group as json array
+         * @param int $id_group = Group id
+         * 
+         * @return json
+         */
+        public function preview (int $id_group)
+        {
+            $return = [
+                'success' => false,
+                'result' => 'Une erreur inconnue est survenue.',
+            ];
+
+            $group = $this->internal_conditional_group->get_for_user($_SESSION['user']['id'], $id_group);
+
+            if (!$group)
+            {
+                $return['result'] = 'Ce groupe n\'existe pas.';
+                echo json_encode($return);
+
+                return false;
+            }
+
+            $contacts = $this->internal_conditional_group->get_contacts_for_condition_and_user($_SESSION['user']['id'], $group['condition']);
+            if (!$contacts)
+            {
+                $return['result'] = 'Aucun contact dans le groupe.';
+                echo json_encode($return);
+
+                return false;
+            }
+
+            $return['success'] = true;
+            $return['result'] = $contacts;
+            echo json_encode($return);
+
+            return true;
+        }
+
         /**
          * Try to get the preview of contacts for a conditionnal group.
          *
diff --git a/controllers/publics/Contact.php b/controllers/publics/Contact.php
index 78da100..69b0cc8 100644
--- a/controllers/publics/Contact.php
+++ b/controllers/publics/Contact.php
@@ -372,6 +372,7 @@ namespace controllers\publics;
                     else
                     {
                         $invalid_type = true;
+                        $result = false;
                     }
             }
 
diff --git a/controllers/publics/Group.php b/controllers/publics/Group.php
index fa8b8af..2bd2c4f 100644
--- a/controllers/publics/Group.php
+++ b/controllers/publics/Group.php
@@ -191,6 +191,45 @@ namespace controllers\publics;
             return $this->redirect(\descartes\Router::url('Group', 'list'));
         }
 
+        /**
+         * Return contacts of a group as json array
+         * @param int $id_group = Group id
+         * 
+         * @return json
+         */
+        public function preview (int $id_group)
+        {
+            $return = [
+                'success' => false,
+                'result' => 'Une erreur inconnue est survenue.',
+            ];
+
+            $group = $this->internal_group->get_for_user($_SESSION['user']['id'], $id_group);
+
+            if (!$group)
+            {
+                $return['result'] = 'Ce groupe n\'existe pas.';
+                echo json_encode($return);
+
+                return false;
+            }
+
+            $contacts = $this->internal_group->get_contacts($id_group);
+            if (!$contacts)
+            {
+                $return['result'] = 'Aucun contact dans le groupe.';
+                echo json_encode($return);
+
+                return false;
+            }
+
+            $return['success'] = true;
+            $return['result'] = $contacts;
+            echo json_encode($return);
+
+            return true;
+        }
+
         /**
          * Cette fonction retourne la liste des groups sous forme JSON.
          */
diff --git a/controllers/publics/Phone.php b/controllers/publics/Phone.php
index 14028ea..7451288 100644
--- a/controllers/publics/Phone.php
+++ b/controllers/publics/Phone.php
@@ -55,6 +55,9 @@ class Phone extends \descartes\Controller
 
         foreach ($phones as &$phone)
         {
+            $limits = $this->internal_phone->get_limits($phone['id']);
+            $phone['limits'] = $limits;
+
             $adapter = $adapters[$phone['adapter']] ?? false;
 
             if (!$adapter)
@@ -131,9 +134,11 @@ class Phone extends \descartes\Controller
      * Create a new phone.
      *
      * @param $csrf : CSRF token
-     * @param string $_POST['name']         : Phone name
-     * @param string $_POST['adapter']      : Phone adapter
-     * @param array  $_POST['adapter_data'] : Phone adapter data
+     * @param string $_POST['name']          : Phone name
+     * @param string $_POST['adapter']       : Phone adapter
+     * @param ?array  $_POST['adapter_data'] : Phone adapter data
+     * @param ?array $_POST['limits']        : Array of limits in number of SMS for a period to be applied to this phone.
+     * @param int $_POST['priority']         : Priority with which to use phone to send SMS. Default 0.
      */
     public function create($csrf)
     {
@@ -146,8 +151,12 @@ class Phone extends \descartes\Controller
 
         $id_user = $_SESSION['user']['id'];
         $name = $_POST['name'] ?? false;
+        $priority = $_POST['priority'] ?? 0;
+        $priority = max(((int) $priority), 0);
         $adapter = $_POST['adapter'] ?? false;
         $adapter_data = !empty($_POST['adapter_data']) ? $_POST['adapter_data'] : [];
+        $limits = $_POST['limits'] ?? [];
+        $limits = is_array($limits) ? $limits : [$limits];
 
         if (!$name || !$adapter)
         {
@@ -156,7 +165,7 @@ class Phone extends \descartes\Controller
             return $this->redirect(\descartes\Router::url('Phone', 'add'));
         }
 
-        $name_exist = $this->internal_phone->get_by_name($name);
+        $name_exist = $this->internal_phone->get_by_name_and_user($id_user, $name);
         if ($name_exist)
         {
             \FlashMessage\FlashMessage::push('danger', 'Ce nom est déjà utilisé pour un autre téléphone.');
@@ -164,6 +173,36 @@ class Phone extends \descartes\Controller
             return $this->redirect(\descartes\Router::url('Phone', 'add'));
         }
 
+        if ($limits)
+        {
+            foreach ($limits as $key => $limit)
+            {
+                if (!is_array($limit))
+                {
+                    unset($limits[$key]);
+                    continue;
+                }
+
+                $startpoint = $limit['startpoint'] ?? false;
+                $volume = $limit['volume'] ?? false;
+
+                if (!$startpoint || !$volume)
+                {
+                    unset($limits[$key]);
+                    continue;
+                }
+
+                $volume = (int) $volume;
+                $limits[$key]['volume'] = max($volume, 1);
+
+                if (!\controllers\internals\Tool::validate_relative_date($startpoint))
+                {
+                    unset($limits[$key]);
+                    continue;
+                }
+            }
+        }
+
         $adapters = $this->internal_adapter->list_adapters();
         $find_adapter = false;
         foreach ($adapters as $metas)
@@ -245,7 +284,7 @@ class Phone extends \descartes\Controller
             return $this->redirect(\descartes\Router::url('Phone', 'add'));
         }
 
-        $success = $this->internal_phone->create($id_user, $name, $adapter, $adapter_data);
+        $success = $this->internal_phone->create($id_user, $name, $adapter, $adapter_data, $priority, $limits);
         if (!$success)
         {
             \FlashMessage\FlashMessage::push('danger', 'Impossible de créer ce téléphone.');
@@ -257,4 +296,207 @@ class Phone extends \descartes\Controller
 
         return $this->redirect(\descartes\Router::url('Phone', 'list'));
     }
+
+
+    /**
+     * Return the edit page for phones
+     *
+     * @param int... $ids : Phones ids
+     */
+    public function edit()
+    {
+        $ids = $_GET['ids'] ?? [];
+        $id_user = $_SESSION['user']['id'];
+
+        $phones = $this->internal_phone->gets_in_for_user($id_user, $ids);
+
+        if (!$phones)
+        {
+            return $this->redirect(\descartes\Router::url('Phone', 'list'));
+        }
+
+        $adapters = $this->internal_adapter->list_adapters();
+
+        foreach ($phones as &$phone)
+        {
+            $limits = $this->internal_phone->get_limits($phone['id']);
+            $phone['limits'] = $limits;
+        }
+
+        $this->render('phone/edit', [
+            'phones' => $phones,
+            'adapters' => $adapters,
+        ]);
+    }
+
+
+    /**
+     * Update multiple phones.
+     *
+     * @param $csrf : CSRF token
+     * @param string $_POST['phones']['id']['name']          : Phone name
+     * @param string $_POST['phones']['id']['adapter']       : Phone adapter
+     * @param ?array $_POST['phones']['id']['adapter_data'] : Phone adapter data
+     * @param ?array $_POST['phones']['id']['limits']        : Array of limits in number of SMS for a period to be applied to this phone.
+     * @param int    $_POST['phones']['id']['priority']         : Priority with which to use phone to send SMS. Default 0.
+     */
+    public function update($csrf)
+    {
+        if (!$this->verify_csrf($csrf))
+        {
+            \FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
+
+            return $this->redirect(\descartes\Router::url('Phone', 'add'));
+        }
+
+        if (!$_POST['phones'])
+        {
+            return $this->redirect(\descartes\Router::url('Phone', 'list'));
+        }
+
+        $id_user = $_SESSION['user']['id'];
+
+        $nb_update = 0;
+        foreach ($_POST['phones'] as $id_phone => $phone)
+        {
+            $name = $phone['name'] ?? false;
+            $priority = $phone['priority'] ?? 0;
+            $priority = max(((int) $priority), 0);
+            $adapter = $phone['adapter'] ?? false;
+            $adapter_data = !empty($phone['adapter_data']) ? $phone['adapter_data'] : [];
+            $limits = $phone['limits'] ?? [];
+            $limits = is_array($limits) ? $limits : [$limits];
+
+            if (!$name || !$adapter)
+            {
+                continue;
+            }
+
+            $phone_with_same_name = $this->internal_phone->get_by_name_and_user($id_user, $name);
+            if ($phone_with_same_name && $phone_with_same_name['id'] != $id_phone)
+            {
+                continue;
+            }
+
+            if ($limits)
+            {
+                foreach ($limits as $key => $limit)
+                {
+                    if (!is_array($limit))
+                    {
+                        unset($limits[$key]);
+                        continue;
+                    }
+                    
+                    $startpoint = $limit['startpoint'] ?? false;
+                    $volume = $limit['volume'] ?? false;
+
+                    if (!$startpoint || !$volume)
+                    {
+                        unset($limits[$key]);
+                        continue;
+                    }
+
+                    $volume = (int) $volume;
+                    $limits[$key]['volume'] = max($volume, 1);
+
+                    if (!\controllers\internals\Tool::validate_relative_date($startpoint))
+                    {
+                        unset($limits[$key]);
+                        continue;
+                    }
+                }
+            }
+
+            $adapters = $this->internal_adapter->list_adapters();
+            $find_adapter = false;
+            foreach ($adapters as $metas)
+            {
+                if ($metas['meta_classname'] === $adapter)
+                {
+                    $find_adapter = $metas;
+
+                    break;
+                }
+            }
+
+            if (!$find_adapter)
+            {
+                continue;
+            }
+
+            if ($find_adapter['meta_hidden'])
+            {
+                continue;
+            }
+
+            //If missing required data fields, error
+            foreach ($find_adapter['meta_data_fields'] as $field)
+            {
+                if (false === $field['required'])
+                {
+                    continue;
+                }
+
+                if (!empty($adapter_data[$field['name']]))
+                {
+                    continue;
+                }
+
+                continue 2;
+            }
+
+            //If field phone number is invalid
+            foreach ($find_adapter['meta_data_fields'] as $field)
+            {
+                if ('phone_number' !== ($field['type'] ?? false))
+                {
+                    continue;
+                }
+
+                if (!empty($adapter_data[$field['name']]))
+                {
+                    $adapter_data[$field['name']] = \controllers\internals\Tool::parse_phone($adapter_data[$field['name']]);
+
+                    if ($adapter_data[$field['name']])
+                    {
+                        continue;
+                    }
+                }
+
+                continue 2;
+            }
+
+            $adapter_data = json_encode($adapter_data);
+
+            //Check adapter is working correctly with thoses names and data
+            $adapter_classname = $find_adapter['meta_classname'];
+            $adapter_instance = new $adapter_classname($adapter_data);
+            $adapter_working = $adapter_instance->test();
+
+            if (!$adapter_working)
+            {
+                continue;
+            }
+
+            $success = $this->internal_phone->update_for_user($id_user, $id_phone, $name, $adapter, $adapter_data, $priority, $limits);
+            if (!$success)
+            {
+                continue;
+            }
+
+            $nb_update ++;
+        }
+
+        if ($nb_update !== \count($_POST['phones']))
+        {
+            \FlashMessage\FlashMessage::push('danger', 'Certains téléphones n\'ont pas pu êtres mis à jour.');
+
+            return $this->redirect(\descartes\Router::url('Phone', 'list'));
+        }
+
+        \FlashMessage\FlashMessage::push('success', 'Tous les téléphones ont été modifiés avec succès.');
+
+        return $this->redirect(\descartes\Router::url('Phone', 'list'));
+    }
 }
diff --git a/controllers/publics/Templating.php b/controllers/publics/Templating.php
index 026622e..a667ee7 100644
--- a/controllers/publics/Templating.php
+++ b/controllers/publics/Templating.php
@@ -83,6 +83,12 @@ namespace controllers\publics;
             $result = $this->internal_templating->render($template, $data);
             $return = $result;
 
+            // If we must force GSM 7 alphabet
+            if ((int) ($_SESSION['user']['settings']['force_gsm_alphabet'] ?? false))
+            {
+                $return['result'] = \controllers\internals\Tool::convert_to_gsm0338($return['result']);
+            }
+
             if (!trim($result['result']))
             {
                 $return['result'] = 'Message vide, il ne sera pas envoyé.';
diff --git a/daemons/Sender.php b/daemons/Sender.php
index 6f0176b..d462739 100644
--- a/daemons/Sender.php
+++ b/daemons/Sender.php
@@ -22,6 +22,7 @@ class Sender extends AbstractDaemon
     private $internal_phone;
     private $internal_scheduled;
     private $internal_received;
+    private $internal_sended;
     private $bdd;
     private $msg_queue;
 
@@ -45,6 +46,7 @@ class Sender extends AbstractDaemon
     {
         //Create the internal controllers
         $this->internal_scheduled = new \controllers\internals\Scheduled($this->bdd);
+        $this->internal_sended = new \controllers\internals\Sended($this->bdd);
 
         //Get smss and transmit order to send to appropriate phone daemon
         $smss_per_scheduled = $this->internal_scheduled->get_smss_to_send();
@@ -62,8 +64,8 @@ class Sender extends AbstractDaemon
     {
         foreach ($smss_per_scheduled as $id_scheduled => $smss)
         {
-            //If queue not  already exists
-            if (!msg_queue_exists(QUEUE_ID_PHONE) || !isset($this->queue))
+            //If queue not already exists
+            if (!msg_queue_exists(QUEUE_ID_PHONE) || !isset($this->msg_queue))
             {
                 $this->msg_queue = msg_get_queue(QUEUE_ID_PHONE);
             }
diff --git a/db/migrations/20230201152658_add_phone_limits.php b/db/migrations/20230201152658_add_phone_limits.php
new file mode 100644
index 0000000..debf233
--- /dev/null
+++ b/db/migrations/20230201152658_add_phone_limits.php
@@ -0,0 +1,43 @@
+<?php
+
+use Phinx\Migration\AbstractMigration;
+
+class AddPhoneLimits extends AbstractMigration
+{
+    /**
+     * Change Method.
+     *
+     * Write your reversible migrations using this method.
+     *
+     * More information on writing migrations is available here:
+     * https://book.cakephp.org/phinx/0/en/migrations.html
+     *
+     * The following commands can be used in this method and Phinx will
+     * automatically reverse them when rolling back:
+     *
+     *    createTable
+     *    renameTable
+     *    addColumn
+     *    addCustomColumn
+     *    renameColumn
+     *    addIndex
+     *    addForeignKey
+     *
+     * Any other destructive changes will result in an error when trying to
+     * rollback the migration.
+     *
+     * Remember to call "create()" or "update()" and NOT "save()" when working
+     * with the Table class.
+     */
+    public function change()
+    {
+        $table = $this->table('phone_limit');
+        $table->addColumn('id_phone', 'integer', ['null' => false])
+              ->addColumn('volume', 'integer', ['null' => false])
+              ->addColumn('startpoint', 'string', ['null' => false, 'limit' => 254]) # A relative time to use as startpoint for counting volume. See https://www.php.net/manual/en/datetime.formats.relative.php
+              ->addColumn('created_at', 'timestamp', ['null' => false, 'default' => 'CURRENT_TIMESTAMP'])
+              ->addColumn('updated_at', 'timestamp', ['null' => true, 'update' => 'CURRENT_TIMESTAMP'])
+              ->addForeignKey('id_phone', 'phone', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE'])
+              ->create();
+    }
+}
diff --git a/db/migrations/20230205214319_add_phone_priority.php b/db/migrations/20230205214319_add_phone_priority.php
new file mode 100644
index 0000000..3ce343b
--- /dev/null
+++ b/db/migrations/20230205214319_add_phone_priority.php
@@ -0,0 +1,43 @@
+<?php
+
+use Phinx\Migration\AbstractMigration;
+
+class AddPhonePriority extends AbstractMigration
+{
+    /**
+     * Change Method.
+     *
+     * Write your reversible migrations using this method.
+     *
+     * More information on writing migrations is available here:
+     * https://book.cakephp.org/phinx/0/en/migrations.html
+     *
+     * The following commands can be used in this method and Phinx will
+     * automatically reverse them when rolling back:
+     *
+     *    createTable
+     *    renameTable
+     *    addColumn
+     *    addCustomColumn
+     *    renameColumn
+     *    addIndex
+     *    addForeignKey
+     *
+     * Any other destructive changes will result in an error when trying to
+     * rollback the migration.
+     *
+     * Remember to call "create()" or "update()" and NOT "save()" when working
+     * with the Table class.
+     */
+    public function change()
+    {
+        $table = $this->table('phone');
+        $table->addColumn('priority', 'integer', [
+                'null' => false,
+                'default' => 0,
+                'comment' => 'Priority with which the phone will be used. The higher the more prioritary.',
+                'after' => 'name'
+            ])
+            ->update();
+    }
+}
diff --git a/env.php.dist b/env.php.dist
index 8f7091b..c544ba0 100644
--- a/env.php.dist
+++ b/env.php.dist
@@ -82,6 +82,7 @@
             'alert_quota_limit_reached' => 1,
             'alert_quota_limit_close' => 0.9,
             'hide_menus' => '',
+            'force_gsm_alphabet' => 0,
         ],
 	];
 
diff --git a/models/Event.php b/models/Event.php
index 843f442..166d46e 100644
--- a/models/Event.php
+++ b/models/Event.php
@@ -84,32 +84,6 @@ namespace models;
             return $this->_select('event', ['id_user' => $id_user], 'at', true, $nb_entry);
         }
 
-        /**
-         * Gets events for a type, since a date and eventually until a date (both included).
-         *
-         * @param int        $id_user : User id
-         * @param string     $type    : Event type we want
-         * @param \DateTime  $since   : Date to get events since
-         * @param ?\DateTime $until   (optional) : Date until wich we want events, if not specified no limit
-         *
-         * @return array
-         */
-        public function get_events_by_type_and_date_for_user(int $id_user, string $type, \DateTime $since, ?\DateTime $until = null)
-        {
-            $where = [
-                'id_user' => $id_user,
-                'type' => $type,
-                '>=at' => $since->format('Y-m-d H:i:s'),
-            ];
-
-            if (null !== $until)
-            {
-                $where['<=at'] = $until->format('Y-m-d H:i:s');
-            }
-
-            return $this->_select('event', $where, 'at');
-        }
-
         /**
          * Return table name.
          */
diff --git a/models/Phone.php b/models/Phone.php
index 14447f4..4579b22 100644
--- a/models/Phone.php
+++ b/models/Phone.php
@@ -15,7 +15,7 @@ namespace models;
     {
 
         /**
-         * Return all hones that belongs to active users
+         * Return all phones that belongs to active users
          *
          * @return array
          */
@@ -63,6 +63,48 @@ namespace models;
             return $this->_select_one('phone', ['name' => $name]);
         }
 
+
+        /**
+         * Return a list of phone limits
+         *
+         * @param int $id_phone : Phone id
+         *
+         * @return array
+         */
+        public function get_limits(int $id_phone)
+        {
+            return $this->_select('phone_limit', ['id_phone' => $id_phone]);
+        }
+
+        /**
+         * Add a limit for a phone.
+         *
+         * @param int $id_phone      : Phone id
+         * @param int $volume        : Limit in volume of SMS
+         * @param string $startpoint :  A relative time to use as startpoint for counting volume. See https://www.php.net/manual/en/datetime.formats.relative.php
+         *
+         * @return mixed (bool|int) : False on error, new row id else
+         */
+        public function insert_phone_limit(int $id_phone, int $volume, string $startpoint)
+        {
+            $success = $this->_insert('phone_limit', ['id_phone' => $id_phone, 'volume' => $volume, 'startpoint' => $startpoint]);
+
+            return $success ? $this->_last_id() : false;
+        }
+
+        /**
+         * Delete limits for a phone
+         *
+         * @param array $id_phone : Phone id
+         *
+         * @return array
+         */
+        public function delete_phone_limits(int $id_phone)
+        {
+            return $this->_delete('phone_limit', ['id_phone' => $id_phone]);
+        }
+
+
         /**
          * Return table name.
          */
diff --git a/models/Sended.php b/models/Sended.php
index b401ccc..0acdb20 100644
--- a/models/Sended.php
+++ b/models/Sended.php
@@ -178,6 +178,20 @@ namespace models;
             return $this->_select_one('sended', ['id_user' => $id_user, 'uid' => $uid, 'adapter' => $adapter]);
         }
 
+        /**
+         * Get number of sended SMS since a date for a phone
+         * 
+         * @param int $id_user : User id
+         * @param int $id_phone : Phone id we want the number of sended message for
+         * @param \DateTime $since : Date since which we want sended number
+         * 
+         * @return int
+         */
+        public function count_since_for_phone_and_user(int $id_user, int $id_phone, \DateTime $since) : int
+        {
+            return $this->_count('sended', ['id_user' => $id_user, 'id_phone' => $id_phone, '>=at' => $since->format('c')]);
+        }
+
         /**
          * Get number of sended SMS for every date since a date for a specific user.
          *
diff --git a/routes.php b/routes.php
index 3eefebd..a5e87cd 100644
--- a/routes.php
+++ b/routes.php
@@ -76,6 +76,7 @@
             'delete' => '/group/delete/{csrf}/',
             'edit' => '/group/edit/',
             'update' => '/group/update/{csrf}/',
+            'preview' => '/group/preview/{id_group}/',
             'json_list' => '/groups.json/',
         ],
         
@@ -88,6 +89,7 @@
             'edit' => '/conditional_group/edit/',
             'update' => '/conditional_group/update/{csrf}/',
             'contacts_preview' => '/conditional_group/preview/',
+            'preview' => '/conditional_group/preview/{id_group}/',
             'json_list' => '/conditional_groups.json/',
         ],
 
@@ -160,6 +162,8 @@
             'add' => '/phone/add/',
             'create' => '/phone/create/{csrf}/',
             'delete' => '/phone/delete/{csrf}/',
+            'edit' => '/phone/edit/',
+            'update' => '/phone/update/{csrf}/',
         ],
         
         'Call' => [
diff --git a/templates/conditional_group/list.php b/templates/conditional_group/list.php
index b688bc4..0ef7726 100644
--- a/templates/conditional_group/list.php
+++ b/templates/conditional_group/list.php
@@ -43,6 +43,7 @@
                                                 <th>Condition</th>
                                                 <th>Date de création</th>
                                                 <th>Dernière modification</th>
+                                                <th>Preview</th>
                                                 <th class="checkcolumn"><input type="checkbox" id="check-all"/></th>
                                             </tr>
                                         </thead>
@@ -69,9 +70,56 @@
 		</div>
 	</div>
 </div>
+<div class="modal fade" tabindex="-1" id="preview-text-modal">
+    <div class="modal-dialog modal-lg">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                <h4 class="modal-title">Prévisualisation des contacts</h4>
+            </div>
+            <div class="modal-body">
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+            </div>
+        </div>
+    </div>
+</div>
 <script>
 jQuery(document).ready(function ()
 {
+    jQuery('body').on('click', '.preview-button', function (e)
+    {
+        e.preventDefault();
+        var group_id = jQuery(this).attr('data-id-group');
+
+        jQuery.ajax({
+            type: "GET",
+            url: HTTP_PWD + '/conditional_group/preview/' + group_id + '/',
+            success: function (data) {
+                if (!data.success) {
+                    jQuery('#preview-text-modal').find('.modal-body').text(data.result);
+                } else {
+                    html = '';
+
+                    for (contact of data.result)
+                    {
+                        html += '<div class="preview-contact well">';
+                        html += '   <div class="preview-contact-name">' + jQuery.fn.dataTable.render.text().display(contact.name) + '</div>'
+                        html += '   <div class="preview-contact-number">' + jQuery.fn.dataTable.render.text().display(contact.number) + '</div>'
+                        html += '   <code class="preview-contact-data">' + jQuery.fn.dataTable.render.text().display(contact.data) + '</code>'
+                        html += '</div>';
+                        console.log(contact);
+                    }
+
+                    jQuery('#preview-text-modal').find('.modal-body').html(html);
+                }
+                jQuery('#preview-text-modal').modal({'keyboard': true});
+            },
+            dataType: 'json'
+        });
+    });
+    
     jQuery('.datatable').DataTable({
         "pageLength": 25,
         "lengthMenu": [[25, 50, 100, 1000, 10000, -1], [25, 50, 100, 1000, 10000, "All"]],
@@ -97,6 +145,12 @@ jQuery(document).ready(function ()
             },
             {data: 'created_at'},
             {data: 'updated_at'},
+            {
+                data: '_',
+                render: function (data, type, row, meta) {
+                    return '<a class="btn btn-info preview-button" href="#" data-id-group="' + jQuery.fn.dataTable.render.text().display(row.id) + '"><span class="fa fa-eye"></span></a>';
+                },
+            },
             {
                 data: 'id',
                 render: function (data, type, row, meta) {
@@ -106,7 +160,6 @@ jQuery(document).ready(function ()
         ],
         "deferRender": true
     });
-
 });
 </script>
 <?php
diff --git a/templates/group/list.php b/templates/group/list.php
index eb1e7c1..5da0452 100644
--- a/templates/group/list.php
+++ b/templates/group/list.php
@@ -43,6 +43,7 @@
                                                 <th>Nombre de contacts</th>
                                                 <th>Date de création</th>
                                                 <th>Dernière modification</th>
+                                                <th>Preview</th>
                                                 <th class="checkcolumn"><input type="checkbox" id="check-all"/></th>
                                             </tr>
                                         </thead>
@@ -69,6 +70,21 @@
 		</div>
 	</div>
 </div>
+<div class="modal fade" tabindex="-1" id="preview-text-modal">
+    <div class="modal-dialog modal-lg">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                <h4 class="modal-title">Prévisualisation des contacts</h4>
+            </div>
+            <div class="modal-body">
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+            </div>
+        </div>
+    </div>
+</div>
 <script>
 jQuery(document).ready(function ()
 {
@@ -92,6 +108,12 @@ jQuery(document).ready(function ()
             {data: 'nb_contact', render: jQuery.fn.dataTable.render.text()},
             {data: 'created_at'},
             {data: 'updated_at'},
+            {
+                data: '_',
+                render: function (data, type, row, meta) {
+                    return '<a class="btn btn-info preview-button" href="#" data-id-group="' + jQuery.fn.dataTable.render.text().display(row.id) + '"><span class="fa fa-eye"></span></a>';
+                },
+            },
             {
                 data: 'id',
                 render: function (data, type, row, meta) {
@@ -102,6 +124,38 @@ jQuery(document).ready(function ()
         "deferRender": true
     });
 
+    jQuery('body').on('click', '.preview-button', function (e)
+    {
+        e.preventDefault();
+        var group_id = jQuery(this).attr('data-id-group');
+
+        jQuery.ajax({
+            type: "GET",
+            url: HTTP_PWD + '/group/preview/' + group_id + '/',
+            success: function (data) {
+                if (!data.success) {
+                    jQuery('#preview-text-modal').find('.modal-body').text(data.result);
+                } else {
+                    html = '';
+
+                    for (contact of data.result)
+                    {
+                        html += '<div class="preview-contact well">';
+                        html += '   <div class="preview-contact-name">' + jQuery.fn.dataTable.render.text().display(contact.name) + '</div>'
+                        html += '   <div class="preview-contact-number">' + jQuery.fn.dataTable.render.text().display(contact.number) + '</div>'
+                        html += '   <code class="preview-contact-data">' + jQuery.fn.dataTable.render.text().display(contact.data) + '</code>'
+                        html += '</div>';
+                        console.log(contact);
+                    }
+
+                    jQuery('#preview-text-modal').find('.modal-body').html(html);
+                }
+                jQuery('#preview-text-modal').modal({'keyboard': true});
+            },
+            dataType: 'json'
+        });
+    });
+
 });
 </script>
 <?php
diff --git a/templates/phone/add.php b/templates/phone/add.php
index f1e08c3..ab2e143 100644
--- a/templates/phone/add.php
+++ b/templates/phone/add.php
@@ -48,7 +48,16 @@
 									</div>
 								</div>
                                 <div class="form-group">
-                                    <label>Type de téléphone : </label>
+                                    <label>Priorité d'utilisation du téléphone</label>
+                                    <p class="italic small help">
+                                        Lors de l'envoi de SMS sans téléphone spécifié, les téléphones avec la plus haute priorité seront utilisés en premier.
+                                    </p>
+									<div class="form-group">
+                                        <input required="required" name="priority" class="form-control" type="number" min="0" placeholder="Priorité d'utilisation" value="<?php $this->s($_SESSION['previous_http_post']['priority'] ?? 0) ?>">
+									</div>
+								</div>
+                                <div class="form-group">
+                                    <label>Type de téléphone</label>
                                     <p class="italic small help" id="description-adapter-general">
                                         Le type de téléphone utilisé par RaspiSMS pour envoyer ou recevoir les SMS. Pour plus d'information, consultez <a href="https://documentation.raspisms.fr/users/adapters/overview.html" target="_blank">la documentation de RaspiSMS</a> concernant les différents types de téléphones.
                                     </p>
@@ -67,7 +76,7 @@
                                         <?php } ?>
                                     </select>
                                 </div>
-                                <div id="adapter-data-container" class="form-group">
+                                <div id="adapter-data-container" class="form-group well">
                                     <div id="adapter-data-description-container">
                                         <h4>Description du téléphone</h4>
                                         <div id="adapter-data-description"></div>
@@ -77,6 +86,15 @@
                                         <h4>Réglages du téléphone</h4>
                                         <div id="adapter-data-fields"></div>
                                     </div>
+                                </div>
+                                <div class="form-group">
+                                    <label>Limites des volumes d'envoi du téléphone</label>
+                                    <p class="italic small help">
+                                        Défini le nombre maximum de SMS qui pourront être envoyés avec ce téléphone sur des périodes de temps données.
+                                    </p>
+                                    <div class="form-group phone-limits-container container-fluid">
+                                        <div class="text-center"><div class="add-phone-limit-button fa fa-plus-circle"></div></div>
+                                    </div>
                                 </div>
 								<a class="btn btn-danger" href="<?php echo \descartes\Router::url('Phone', 'list'); ?>">Annuler</a>
 								<input type="submit" class="btn btn-success" value="Enregistrer le téléphone" /> 	
@@ -174,6 +192,47 @@
         {
             change_adapter();
         });
+
+        jQuery('body').on('click', '.phone-limits-group-remove', function (e)
+        {
+            e.preventDefault();
+            jQuery(this).parent('.phone-limits-group').remove();
+            return false;
+        });
+
+        jQuery('body').on('click', '.add-phone-limit-button', function(e)
+        {
+            var random_id = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
+			var newLimit = '' +
+			'<div class="row phone-limits-group">'+
+                '<div class="col-xs-4">'+
+                    '<label>Période</label><br/>'+
+                    '<select name="limits[' + random_id + '][startpoint]" class="form-control" required>'+
+                        '<option value="" disabled selected>Période sur laquelle appliquer la limite</option>'+
+                        '<option value="today">Par jour</option>'+
+                        '<option value="-24 hours">24 heures glissantes</option>'+
+                        '<option value="this week midnight">Cette semaine</option>'+
+                        '<option value="-7 days">7 jours glissants</option>'+
+                        '<option value="this week midnight -1 week">Ces deux dernières semaines</option>'+
+                        '<option value="-14 days">14 jours glissants</option>'+
+                        '<option value="this month midnight">Ce mois</option>'+
+                        '<option value="-1 month">1 mois glissant</option>'+
+                        '<option value="-28 days">28 jours glissants</option>'+
+                        '<option value="-30 days">30 jours glissants</option>'+
+                        '<option value="-31 days">31 jours glissants</option>'+
+                    '</select>'+
+                '</div>'+
+                '<div class="scheduleds-number-data-container col-xs-8">'+
+                    '<label>Volume</label>'+
+                    '<div class="form-group">'+
+                        '<input name="limits[' + random_id + '][volume]" class="form-control" type="number" min="1" placeholder="Nombre de SMS maximum sur la période.">'+
+                    '</div>'+
+                '</div>'+
+                '<a href="#" class="phone-limits-group-remove"><span class="fa fa-times"></span></a>'+
+            '</div>';
+
+            jQuery(this).parent('div').before(newLimit);
+        });
 	});
 </script>
 <?php
diff --git a/templates/phone/edit.php b/templates/phone/edit.php
new file mode 100644
index 0000000..a1b2446
--- /dev/null
+++ b/templates/phone/edit.php
@@ -0,0 +1,304 @@
+<?php
+	//Template dashboard
+	
+	$this->render('incs/head', ['title' => 'Phones - Edit'])
+?>
+<div id="wrapper">
+<?php
+	$this->render('incs/nav', ['page' => 'phones'])
+?>
+	<div id="page-wrapper">
+		<div class="container-fluid">
+			<!-- Page Heading -->
+			<div class="row">
+				<div class="col-lg-12">
+					<h1 class="page-header">
+						Modification téléphones
+					</h1>
+					<ol class="breadcrumb">
+						<li>
+							<i class="fa fa-dashboard"></i> <a href="<?php echo \descartes\Router::url('Dashboard', 'show'); ?>">Dashboard</a>
+						</li>
+						<li>
+							<i class="fa fa-phone"></i> <a href="<?php echo \descartes\Router::url('Phone', 'list'); ?>">Téléphones</a>
+						</li>
+						<li class="active">
+							<i class="fa fa-edit"></i> Modifier
+						</li>
+					</ol>
+				</div>
+			</div>
+			<!-- /.row -->
+
+			<div class="row">
+				<div class="col-lg-12">
+					<div class="panel panel-default">
+						<div class="panel-heading">
+							<h3 class="panel-title"><i class="fa fa-phone fa-fw"></i> Modification de téléphones</h3>
+						</div>
+						<div class="panel-body">
+							<form action="<?php echo \descartes\Router::url('Phone', 'update', ['csrf' => $_SESSION['csrf']]);?>" method="POST">
+                                <?php foreach ($phones as $phone) { ?>
+                                    <div class="entry-container" data-entry-id="<?php $this->s($phone['id']); ?>">
+                                        <div class="form-group">
+                                            <label>Nom du téléphone</label>
+                                            <p class="italic small help">
+                                                Le nom du téléphone qui enverra et recevra les messages.
+                                            </p>
+                                            <div class="form-group">
+                                            <input required="required" name="phones[<?php $this->s($phone['id']); ?>][name]" class="form-control" placeholder="Nom du téléphone" value="<?php $this->s($phone['name']); ?>">
+                                            </div>
+                                        </div>
+                                        <div class="form-group">
+                                            <label>Priorité d'utilisation du téléphone</label>
+                                            <p class="italic small help">
+                                                Lors de l'envoi de SMS sans téléphone spécifié, les téléphones avec la plus haute priorité seront utilisés en premier.
+                                            </p>
+                                            <div class="form-group">
+                                                <input required="required" name="phones[<?php $this->s($phone['id']); ?>][priority]" class="form-control" type="number" min="0" placeholder="Priorité d'utilisation" value="<?php $this->s($phone['priority']) ?>">
+                                            </div>
+                                        </div>
+                                        <div class="form-group">
+                                            <label>Type de téléphone</label>
+                                            <p class="italic small help description-adapter-general">
+                                                Le type de téléphone utilisé par RaspiSMS pour envoyer ou recevoir les SMS. Pour plus d'information, consultez <a href="https://documentation.raspisms.fr/users/adapters/overview.html" target="_blank">la documentation de RaspiSMS</a> concernant les différents types de téléphones.
+                                            </p>
+                                            <select name="phones[<?php $this->s($phone['id']); ?>][adapter]" class="form-control adapter-select">
+                                                <?php foreach ($adapters as $adapter) { ?>
+                                                    <?php if ($adapter['meta_hidden'] === false) { ?>
+                                                        <option 
+                                                            value="<?= $adapter['meta_classname'] ?>"
+                                                            data-description="<?php $this->s($adapter['meta_description']); ?>"
+                                                            data-data-fields="<?php $this->s(json_encode($adapter['meta_data_fields'])); ?>"
+                                                            <?php if ($phone['adapter'] == $adapter['meta_classname']) { ?>
+                                                                data-phone-adapter-data="<?php $this->s($phone['adapter_data']); ?>"
+                                                                selected
+                                                            <?php } ?>
+                                                        >
+                                                            <?php $this->s($adapter['meta_name']); ?>
+                                                        </option>
+                                                    <?php } ?>
+                                                <?php } ?>
+                                            </select>
+                                        </div>
+                                        <div class="form-group well adapter-data-container">
+                                            <div class="adapter-data-description-container">
+                                                <h4>Description du téléphone</h4>
+                                                <div class="adapter-data-description"></div>
+                                            </div>
+                                            
+                                            <div class="adapter-data-fields-container">
+                                                <h4>Réglages du téléphone</h4>
+                                                <div class="adapter-data-fields"></div>
+                                            </div>
+                                        </div>
+                                        <div class="form-group">
+                                            <label>Limites des volumes d'envoi du téléphone</label>
+                                            <p class="italic small help">
+                                                Défini le nombre maximum de SMS qui pourront être envoyés avec ce téléphone sur des périodes de temps données.
+                                            </p>
+                                            <div class="form-group phone-limits-container container-fluid">
+                                                <?php foreach ($phone['limits'] as $limit) { ?>
+                                                    <div class="row phone-limits-group">
+                                                        <div class="col-xs-4">
+                                                            <label>Période</label><br/>
+                                                            <?php $random_id = uniqid(); ?>
+                                                            <select name="phones[<?= $phone['id']; ?>][limits][<?= $random_id; ?>][startpoint]" class="form-control" required>
+                                                                <option value="" disabled selected>Période sur laquelle appliquer la limite</option>
+                                                                <option <?= $limit['startpoint'] == 'today' ? 'selected' : ''; ?> value="today">Par jour</option>
+                                                                <option <?= $limit['startpoint'] == '-24 hours' ? 'selected' : ''; ?> value="-24 hours">24 heures glissantes</option>
+                                                                <option <?= $limit['startpoint'] == 'this week midnight' ? 'selected' : ''; ?> value="this week midnight">Cette semaine</option>
+                                                                <option <?= $limit['startpoint'] == '-7 days' ? 'selected' : ''; ?> value="-7 days">7 jours glissants</option>
+                                                                <option <?= $limit['startpoint'] == 'this week midnight -1 week' ? 'selected' : ''; ?> value="this week midnight -1 week">Ces deux dernières semaines</option>
+                                                                <option <?= $limit['startpoint'] == '-14 days' ? 'selected' : ''; ?> value="-14 days">14 jours glissants</option>
+                                                                <option <?= $limit['startpoint'] == 'this month midnight' ? 'selected' : ''; ?> value="this month midnight">Ce mois</option>
+                                                                <option <?= $limit['startpoint'] == '-1 month' ? 'selected' : ''; ?> value="-1 month">1 mois glissant</option>
+                                                                <option <?= $limit['startpoint'] == '-28 days' ? 'selected' : ''; ?> value="-28 days">28 jours glissants</option>
+                                                                <option <?= $limit['startpoint'] == '-30 days' ? 'selected' : ''; ?> value="-30 days">30 jours glissants</option>
+                                                                <option <?= $limit['startpoint'] == '-31 days' ? 'selected' : ''; ?> value="-31 days">31 jours glissants</option>
+                                                            </select>
+                                                        </div>
+                                                        <div class="scheduleds-number-data-container col-xs-8">
+                                                            <label>Volume</label>
+                                                            <div class="form-group">
+                                                                <input name="phones[<?= $phone['id']; ?>][limits][<?= $random_id; ?>][volume]" class="form-control" type="number" min="1" value="<?php $this->s($limit['volume']); ?>" placeholder="Nombre de SMS maximum sur la période.">
+                                                            </div>
+                                                        </div>
+                                                        <a href="#" class="phone-limits-group-remove"><span class="fa fa-times"></span></a>
+                                                    </div>
+                                                <?php } ?>
+                                                <div class="text-center"><div class="add-phone-limit-button fa fa-plus-circle"></div></div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                    <hr/>
+                                <?php } ?>
+								<a class="btn btn-danger" href="<?php echo \descartes\Router::url('Phone', 'list'); ?>">Annuler</a>
+								<input type="submit" class="btn btn-success" value="Enregistrer le téléphone" /> 	
+							</form>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+</div>
+<script>
+
+    function change_adapter (target)
+    {
+        var phone_id = target.parents('.entry-container').attr('data-entry-id');
+
+        var option = target.find('option:selected');
+        target.parents('.entry-container').find('.adapter-data-description').html(option.attr('data-description'));
+        target.parents('.entry-container').find('.description-adapter-data').text(option.attr('data-data-help'));
+    
+        var data_fields = option.attr('data-data-fields');
+        data_fields = JSON.parse(data_fields);
+
+        if (option.attr('data-phone-adapter-data'))
+        {
+            var phone_adapter_data = option.attr('data-phone-adapter-data');
+            phone_adapter_data = JSON.parse(phone_adapter_data);
+        }
+
+        var numbers = [];
+
+        var html = '';
+        jQuery.each(data_fields, function (index, field)
+        {
+            if (phone_adapter_data)
+            {
+                if (field.name in phone_adapter_data)
+                {
+                    value = phone_adapter_data[field.name];
+                }
+                else
+                {
+                    value = field.default_value ? field.default_value : null;
+                }
+            }
+            else
+            {
+                value = field.default_value ? field.default_value : null;
+            }
+            
+
+            if (field.type == 'phone_number')
+            {
+                var random_id = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
+                html += '' +
+                '<div class="form-group">' +
+                    '<label>' + field.title + '</label>' +
+                    '<p class="italic small help">' + field.description + '</p>' +
+                    '<div class="form-group">' + 
+                        '<input name="" class="form-control phone-international-input" type="tel" id="' + random_id + '" ' + (field.required ? 'required' : '') + ' ' + (value ? 'value="' + value + '"' :  '') + '>' +
+                    '</div>' +
+                '</div>';
+
+                var number = {
+                    'id': random_id, 
+                    'name': field.name,
+                };
+
+                numbers.push(number);
+            }
+            else if (field.type == 'boolean')
+            {
+                html += '' + 
+                '<div class="form-group">' +
+                    '<label>' + field.title + '</label>' +
+                    '<p class="italic small help">' + field.description + '</p>' +
+                    '<div class="form-group">' + 
+                        '<input type="checkbox" name="phones[' + phone_id + '][adapter_data][' + field.name + ']" class="form-control" ' + (field.required ? 'required' : '') + ' ' + (value ? 'value="' + value + '" checked' :  'value="1"') +  '><label class="switch" for="adapter_data[' + field.name + ']"></label>' +
+                    '</div>' +
+                '</div>';
+            }
+            else
+            {
+                html += '' + 
+                '<div class="form-group">' +
+                    '<label>' + field.title + '</label>' +
+                    '<p class="italic small help">' + field.description + '</p>' +
+                    '<div class="form-group">' + 
+                        '<input name="phones[' + phone_id + '][adapter_data][' + field.name + ']" class="form-control" ' + (field.required ? 'required' : '') + ' ' + (value ? 'value="' + value + '"' :  '') +  '>' +
+                    '</div>' +
+                '</div>';
+            }
+        });
+
+        if (html == '')
+        {
+            html = 'Pas de réglages.';
+        }
+
+        target.parents('.entry-container').find('.adapter-data-fields').html(html);
+        
+        for (i = 0; i < numbers.length; i++)
+        {
+            var iti_number_input = window.intlTelInput(document.getElementById(numbers[i].id), {
+                hiddenInput: 'phones[' + phone_id + '][adapter_data][' + numbers[i].name + ']',
+                defaultCountry: '<?php $this->s($_SESSION['user']['settings']['default_phone_country']); ?>',
+                preferredCountries: <?php $this->s(json_encode(explode(',', $_SESSION['user']['settings']['preferred_phone_country'])), false, false); ?>,
+                nationalMode: true,
+                utilsScript: '<?php echo HTTP_PWD_JS; ?>/intlTelInput/utils.js',
+            });
+        }
+    }
+
+	jQuery('document').ready(function($)
+    {
+        jQuery('.adapter-select').each(function () {
+            change_adapter(jQuery(this));
+        });
+
+        jQuery('.adapter-select').on('change', function (e)
+        {
+            change_adapter(jQuery(this));
+        });
+
+        jQuery('body').on('click', '.phone-limits-group-remove', function (e)
+        {
+            e.preventDefault();
+            jQuery(this).parent('.phone-limits-group').remove();
+            return false;
+        });
+
+        jQuery('body').on('click', '.add-phone-limit-button', function(e)
+        {
+            var phone_id = jQuery(this).parents('.entry-container').attr('data-entry-id');
+            var random_id = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
+			var newLimit = '' +
+			'<div class="row phone-limits-group">'+
+                '<div class="col-xs-4">'+
+                    '<label>Période</label><br/>'+
+                    '<select name="phones[' + phone_id + '][limits][' + random_id + '][startpoint]" class="form-control adapter-select" required>'+
+                        '<option value="" disabled selected>Période sur laquelle appliquer la limite</option>'+
+                        '<option value="today">Par jour</option>'+
+                        '<option value="-24 hours">24 heures glissantes</option>'+
+                        '<option value="this week midnight">Cette semaine</option>'+
+                        '<option value="-7 days">7 jours glissants</option>'+
+                        '<option value="this week midnight -1 week">Ces deux dernières semaines</option>'+
+                        '<option value="-14 days">14 jours glissants</option>'+
+                        '<option value="this month midnight">Ce mois</option>'+
+                        '<option value="-1 month">1 mois glissant</option>'+
+                        '<option value="-28 days">28 jours glissants</option>'+
+                        '<option value="-30 days">30 jours glissants</option>'+
+                        '<option value="-31 days">31 jours glissants</option>'+
+                    '</select>'+
+                '</div>'+
+                '<div class="scheduleds-number-data-container col-xs-8">'+
+                    '<label>Volume</label>'+
+                    '<div class="form-group">'+
+                        '<input name="phones[' + phone_id + '][limits][' + random_id + '][volume]" class="form-control" type="number" min="1" placeholder="Nombre de SMS maximum sur la période.">'+
+                    '</div>'+
+                '</div>'+
+                '<a href="#" class="phone-limits-group-remove"><span class="fa fa-times"></span></a>'+
+            '</div>';
+
+            jQuery(this).parent('div').before(newLimit);
+        });
+	});
+</script>
+<?php
+	$this->render('incs/footer');
diff --git a/templates/phone/list.php b/templates/phone/list.php
index c505a45..59a701c 100644
--- a/templates/phone/list.php
+++ b/templates/phone/list.php
@@ -41,8 +41,10 @@
                                             <tr>
                                                 <th>ID</th>
                                                 <th>Nom</th>
+                                                <th>Priorité</th>
                                                 <th>Type de téléphone</th>
                                                 <th>Callbacks</th>
+                                                <th>Limites</th>
                                                 <th class="checkcolumn"><input type="checkbox" id="check-all"/></th>
                                             </tr>
                                         </thead>
@@ -56,6 +58,7 @@
                                     </div>
                                     <div class="text-right col-xs-6 no-padding">
                                         <strong>Action pour la séléction :</strong>
+                                        <button class="btn btn-default" type="submit" formaction="<?php echo \descartes\Router::url('Phone', 'edit'); ?>"><span class="fa fa-edit"></span> Modifier</button>
                                         <button class="btn btn-default btn-confirm" type="submit" formaction="<?php echo \descartes\Router::url('Phone', 'delete', ['csrf' => $_SESSION['csrf']]); ?>"><span class="fa fa-trash-o"></span> Supprimer</button>
                                     </div>
                                 </div>
@@ -88,6 +91,7 @@ jQuery(document).ready(function ()
         "columns" : [
             {data: 'id', render: jQuery.fn.dataTable.render.text()},
             {data: 'name', render: jQuery.fn.dataTable.render.text()},
+            {data: 'priority', render: jQuery.fn.dataTable.render.text()},
             {data: 'adapter', render: jQuery.fn.dataTable.render.text()},
             {
                 data: '_',
@@ -123,6 +127,61 @@ jQuery(document).ready(function ()
                     return html;
                 },
             },
+            {
+                data: 'limits',
+                render: function (limits) {
+                    if (!limits.length)
+                    {
+                        return 'Pas de limites.';
+                    }
+
+                    var html = '';
+                    for (limit of limits)
+                    {
+                        switch (limit.startpoint)
+                        {
+                            case "today" : 
+                                var startpoint = 'Par jour';
+                                break;
+                            case "-24 hours" : 
+                                var startpoint = '24 heures glissantes';
+                                break;
+                            case "this week midnight" : 
+                                var startpoint = 'Cette semaine';
+                                break;
+                            case "-7 days" : 
+                                var startpoint = '7 jours glissants';
+                                break;
+                            case "this week midnight -1 week" : 
+                                var startpoint = 'Ces deux dernières semaines';
+                                break;
+                            case "-14 days" : 
+                                var startpoint = '14 jours glissants';
+                                break;
+                            case "this month midnight" : 
+                                var startpoint = 'Ce mois';
+                                break;
+                            case "-1 month" : 
+                                var startpoint = '1 mois glissant';
+                                break;
+                            case "-28 days" : 
+                                var startpoint = '28 jours glissants';
+                                break;
+                            case "-30 days" : 
+                                var startpoint = '30 jours glissants';
+                                break;
+                            case "-31 days" : 
+                                var startpoint = '31 jours glissants';
+                                break;
+                            default : 
+                                var startpoint = 'Inconnu'
+                        }
+                        html += '<div><span class="bold">' + jQuery.fn.dataTable.render.text().display(startpoint) + ' : </span>' + jQuery.fn.dataTable.render.text().display(limit.volume) + '</div>';
+                    }
+
+                    return html;
+                },
+            },
             {
                 data: 'id',
                 render: function (data, type, row, meta) {
diff --git a/templates/setting/show.php b/templates/setting/show.php
index 7a6325a..afe8cff 100644
--- a/templates/setting/show.php
+++ b/templates/setting/show.php
@@ -54,6 +54,25 @@
 										</form>
 									</div>
                                 </div>
+                                <div class="panel panel-default">
+									<div class="panel-heading">
+										<h4 class="panel-title"><i class="fa fa-font fa-fw"></i> Alphabet SMS optimisé</h4>
+									</div>
+									<div class="panel-body">
+										<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'force_gsm_alphabet', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
+											<div class="form-group">
+												<label>Optimiser la taille des SMS en remplaçant les caractères spéciaux par leur équivalent GSM 7-bit : </label>
+												<select name="setting_value" class="form-control">
+													<option value="0">Non</option>
+													<option value="1" <?php echo $_SESSION['user']['settings']['force_gsm_alphabet'] ? 'selected' : ''; ?>>Oui</option>
+												</select>
+											</div>	
+											<div class="text-center">
+												<button class="btn btn-success">Mettre à jour les données</button>	
+											</div>
+										</form>
+									</div>
+								</div>
 								<div class="panel panel-default">
 									<div class="panel-heading">
 										<h4 class="panel-title"><i class="fa fa-picture-o fa-fw"></i> Support des MMS</h4>
diff --git a/tests/phpstan/phpstan.phar b/tests/phpstan/phpstan.phar
index 19bead9..aee0930 100644
Binary files a/tests/phpstan/phpstan.phar and b/tests/phpstan/phpstan.phar differ