diff --git a/mail/personal/mail/class_MailQuotaAttribute.inc b/mail/personal/mail/class_MailQuotaAttribute.inc
index bdf9b8fec3b3bc433ebc4db25b91cd339c4318a7..a8191086b5f172d6cec7b6da23de0964ad97ff40 100644
--- a/mail/personal/mail/class_MailQuotaAttribute.inc
+++ b/mail/personal/mail/class_MailQuotaAttribute.inc
@@ -21,7 +21,16 @@
 
 class MailQuotaAttribute extends UnitIntAttribute
 {
+  /**
+   * @var int Quota usage in MiB, -1 if unknown
+   */
   private $quotaUsage;
+  /**
+   * @var string Quota limit in MiB, empty string if unlimited
+   *
+   * The same as $this->value, unless there is an inherited group limit
+   */
+  private $quotaLimit;
 
   function __construct ($label, $description, $ldapName, $required, $min = FALSE, $max = FALSE, $defaultValue = "", $acl = "")
   {
@@ -39,6 +48,7 @@ class MailQuotaAttribute extends UnitIntAttribute
       /* Read quota */
       $this->setValue((string) $mailMethod->getQuota($this->getValue()));
       $this->quotaUsage = $mailMethod->getQuotaUsage();
+      $this->quotaLimit = $mailMethod->getQuotaLimit($this->getValue());
     } catch (MailMethodError $e) {
       $error = new SimplePluginError(
         $this,
@@ -60,7 +70,7 @@ class MailQuotaAttribute extends UnitIntAttribute
       'htmlid'        => $this->getHtmlId().'_usage',
       'label'         => '{literal}'._('Quota usage').'{/literal}',
       'description'   => _('Part of the quota which is used'),
-      'input'         => static::quotaToImage($this->quotaUsage, $this->getValue()),
+      'input'         => static::quotaToImage($this->quotaUsage, $this->quotaLimit),
       'subattribute'  => FALSE,
       'required'      => FALSE,
       'readable'      => $readable,
@@ -68,15 +78,16 @@ class MailQuotaAttribute extends UnitIntAttribute
     ];
   }
 
-  static function quotaToImage ($use, $quota): string
+  static function quotaToImage (int $use, string $quota): string
   {
     if ($use == -1) {
-      return '  '._('Unknown');
+      return '  '.htmlescape(_('Unknown'));
     } elseif (empty($quota)) {
-      return '  '._('Unlimited');
+      return '  '.htmlescape(sprintf(_('Unlimited (%dMiB used)'), $use));
     } else {
       $usage = round(($use / $quota) * 100);
-      return '<img src="progress.php?x=100&amp;y=17&amp;p='.$usage.'" alt="'.$usage.'%"/>';
+      $alt = htmlescape(sprintf(_('%d%% (%dMiB)'), $usage, $use));
+      return '<img src="progress.php?x=100&amp;y=17&amp;p='.$usage.'" alt="'.$alt.'" title="'.$alt.'"/>';
     }
   }
 }
diff --git a/mail/personal/mail/class_mail-methods.inc b/mail/personal/mail/class_mail-methods.inc
index a8d6510a87e46bbcbfcc3bc5c82da5a8b7143d93..a2e39198af2258d2fe0ccae62d7606c8fa18d002 100644
--- a/mail/personal/mail/class_mail-methods.inc
+++ b/mail/personal/mail/class_mail-methods.inc
@@ -269,7 +269,7 @@ class mailMethod
     return -1;
   }
 
-  /*! \brief  Returns the quota restrictions.
+  /*! \brief  Returns the quota restrictions specific to this user.
       @return string quota value, numeric string or empty string
    */
   public function getQuota (string $quotaValue): string
@@ -277,6 +277,14 @@ class mailMethod
     return $quotaValue;
   }
 
+  /*! \brief  Returns the quota restrictions specific or inherited by this user.
+      @return string quota value, numeric string or empty string
+   */
+  public function getQuotaLimit (string $quotaValue): string
+  {
+    return $quotaValue;
+  }
+
   /*! \brief  Sets the mail quota
    */
   public function setQuota (string $number)
diff --git a/mail/personal/mail/class_mailTabPlugin.inc b/mail/personal/mail/class_mailTabPlugin.inc
index 192355c07f83576733641a5db17beef5b3391883..64ba695e023a417f2ba5606032f8ad21b8007e23 100644
--- a/mail/personal/mail/class_mailTabPlugin.inc
+++ b/mail/personal/mail/class_mailTabPlugin.inc
@@ -70,7 +70,7 @@ class mailTabPlugin extends simplePlugin
 
   public function mailServerChanged ()
   {
-    $this->mailMethod = mailMethod::getInstanceFromServer($this->gosaMailServer, $this);
+    $this->mailMethod = mailMethod::getInstanceFromServer($this->attributesAccess[$this->serverAttr]->getValue(), $this);
     if ($this->initialMailMethod === NULL) {
       $this->initialMailMethod = $this->mailMethod;
     }
diff --git a/zimbra/personal/mail/mail-methods/class_mail-methods-zimbra.inc b/zimbra/personal/mail/mail-methods/class_mail-methods-zimbra.inc
index f63c534ba6c27ba405c46673d38fe36b552e0d74..6a358f50682c7f4c1a5bdebe9408ddea59039720 100644
--- a/zimbra/personal/mail/mail-methods/class_mail-methods-zimbra.inc
+++ b/zimbra/personal/mail/mail-methods/class_mail-methods-zimbra.inc
@@ -682,8 +682,11 @@ class mailMethodZimbra extends mailMethod
   public function getQuota (string $quotaValue): string
   {
     if ($this->cacheAccount()) {
-      /* Server sends quota in bytes */
-      if (isset($this->cachedAccount['account']['zimbraMailQuota']) && is_numeric($this->cachedAccount['account']['zimbraMailQuota'])) {
+      if (
+        isset($this->cachedAccount['account']['zimbraMailQuota']) &&
+        is_numeric($this->cachedAccount['account']['zimbraMailQuota'])
+      ) {
+        /* Server sends quota in bytes */
         return (string)floor($this->cachedAccount['account']['zimbraMailQuota'] / (1024 * 1024));
       } else {
         return '';
@@ -692,6 +695,35 @@ class mailMethodZimbra extends mailMethod
     return $quotaValue;
   }
 
+  /*! \brief  Returns the quota restrictions specific or inherited by this user.
+      @return string quota value, numeric string or empty string
+   */
+  public function getQuotaLimit (string $quotaValue): string
+  {
+    if (empty($quotaValue) && $this->cacheAccount()) {
+      if (
+        isset($this->cachedAccount['account']['zimbraCOSId']) &&
+        ($this->cachedAccount['account']['zimbraCOSId'] !== '')
+      ) {
+        $cosOptions = $this->getCosOptions();
+        foreach ($cosOptions as $cosOption) {
+          if ($cosOption['id'] === $this->cachedAccount['account']['zimbraCOSId']) {
+            if (
+              isset($cosOption['attributes']['zimbraMailQuota']) &&
+              is_numeric($cosOption['attributes']['zimbraMailQuota']) &&
+              ($cosOption['attributes']['zimbraMailQuota'] > 0)
+            ) {
+              /* Server sends quota in bytes */
+              return (string)floor($cosOption['attributes']['zimbraMailQuota'] / (1024 * 1024));
+            }
+            break;
+          }
+        }
+      }
+    }
+    return $quotaValue;
+  }
+
   public function additionalAttributes (string $acl): array
   {
     $attributes = [];
@@ -716,6 +748,18 @@ class mailMethodZimbra extends mailMethod
           (isset($this->cachedAccount['account']['zimbraAccountStatus']) ? $this->cachedAccount['account']['zimbraAccountStatus'] : _('Unknown')),
           $acl
         );
+        $cosLimit = $this->getQuotaLimit('');
+        if ($cosLimit !== '') {
+          array_unshift(
+            $attributes,
+            new DisplayAttribute(
+              _('COS quota'), _('Quota limit set in the class of service'),
+              'zimbraCOSQuota', FALSE,
+              sprintf(_('%sMiB'), $cosLimit),
+              $acl
+            )
+          );
+        }
       }
       $cosOptions = $this->getCosOptions();
       $choices  = [];
diff --git a/zimbra/personal/mail/mail-methods/zimbraSoap.php b/zimbra/personal/mail/mail-methods/zimbraSoap.php
index 92be3b1cf6d6edb3223924cc32bf4a2fe6d3ca02..fabc24ef79485576bdc9b554bbb157243dabe9db 100644
--- a/zimbra/personal/mail/mail-methods/zimbraSoap.php
+++ b/zimbra/personal/mail/mail-methods/zimbraSoap.php
@@ -390,7 +390,7 @@ class getAllCosResponse extends Response {
   {
     return array_map(
       function($cos) {
-        return ['id' => $cos->id, 'name' => $cos->name];
+        return ['id' => $cos->id, 'name' => $cos->name, 'attributes' => static::attributesListToArray($cos->a)];
       },
       $this->cos
     );