diff --git a/bigbluebutton-html5/imports/ui/components/chat/component.jsx b/bigbluebutton-html5/imports/ui/components/chat/component.jsx
index 6c1cec82e9bb723415fa38b2ed420d569d87211c..4de0c264927ebb3da354186eb5e6273e039a9698 100755
--- a/bigbluebutton-html5/imports/ui/components/chat/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/chat/component.jsx
@@ -35,6 +35,8 @@ class Chat extends Component {
       lastReadMessageTime,
       partnerIsLoggedOut,
       isChatLocked,
+      minMessageLength,
+      maxMessageLength,
       actions,
       intl,
     } = this.props;
@@ -81,6 +83,8 @@ class Chat extends Component {
           chatAreaId={ELEMENT_ID}
           chatTitle={title}
           chatName={chatName}
+          minMessageLength={minMessageLength}
+          maxMessageLength={maxMessageLength}
           handleSendMessage={actions.handleSendMessage}
         />
       </div>
diff --git a/bigbluebutton-html5/imports/ui/components/chat/container.jsx b/bigbluebutton-html5/imports/ui/components/chat/container.jsx
index e4705b2976db00564f20aa027d1b1e351e93f8c6..e114314e66ce6c013456ea97c1465d233fa677a4 100755
--- a/bigbluebutton-html5/imports/ui/components/chat/container.jsx
+++ b/bigbluebutton-html5/imports/ui/components/chat/container.jsx
@@ -99,13 +99,14 @@ export default injectIntl(createContainer(({ params, intl }) => {
     partnerIsLoggedOut,
     isChatLocked,
     scrollPosition,
+    minMessageLength: CHAT_CONFIG.min_message_length,
+    maxMessageLength: CHAT_CONFIG.max_message_length,
     actions: {
-
       handleClosePrivateChat: chatID => ChatService.closePrivateChat(chatID),
 
       handleSendMessage: message => {
         ChatService.updateScrollPosition(chatID, null);
-        let sentMessage = ChatService.sendMessage(chatID, message);
+        return ChatService.sendMessage(chatID, message);
       },
 
       handleScrollUpdate: position => ChatService.updateScrollPosition(chatID, position),
diff --git a/bigbluebutton-html5/imports/ui/components/chat/message-form/component.jsx b/bigbluebutton-html5/imports/ui/components/chat/message-form/component.jsx
index 2c0dd9e2a99d1841ea9758851a93d2f0ca390479..c839510da98a183a4da7c5bfb52bbd4173219c58 100755
--- a/bigbluebutton-html5/imports/ui/components/chat/message-form/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/chat/message-form/component.jsx
@@ -27,6 +27,12 @@ const messages = defineMessages({
     id: 'app.chat.inputPlaceholder',
     description: 'Chat message input placeholder',
   },
+  errorMinMessageLength: {
+    id: 'app.chat.errorMinMessageLength',
+  },
+  errorMaxMessageLength: {
+    id: 'app.chat.errorMaxMessageLength',
+  },
 });
 
 class MessageForm extends Component {
@@ -35,6 +41,8 @@ class MessageForm extends Component {
 
     this.state = {
       message: '',
+      error: '',
+      hasErrors: false,
     };
 
     this.handleMessageChange = this.handleMessageChange.bind(this);
@@ -44,7 +52,6 @@ class MessageForm extends Component {
   }
 
   handleMessageKeyDown(e) {
-
     //TODO Prevent send message pressing enter on mobile and/or virtual keyboard
     if (e.keyCode === 13 && !e.shiftKey) {
       e.preventDefault();
@@ -59,73 +66,98 @@ class MessageForm extends Component {
   }
 
   handleMessageChange(e) {
-    this.setState({ message: e.target.value });
+    const { intl } = this.props;
+
+    const message = e.target.value;
+    let error = '';
+
+    const { minMessageLength, maxMessageLength, } = this.props;
+
+    if (message.length < minMessageLength) {
+      error = intl.formatMessage(messages.errorMinMessageLength,
+        { 0: minMessageLength - message.length });
+    }
+
+    if (message.length > maxMessageLength) {
+      error = intl.formatMessage(messages.errorMaxMessageLength,
+        { 0: message.length - maxMessageLength });
+    }
+
+    this.setState({
+      message,
+      error,
+    });
   }
 
   handleSubmit(e) {
     e.preventDefault();
 
-    const { disabled } = this.props;
+    const { disabled, minMessageLength, maxMessageLength, } = this.props;
+    let message = this.state.message.trim();
 
-    if (disabled) {
+    if (disabled
+      || message.length === 0
+      || message.length < minMessageLength
+      || message.length > maxMessageLength) {
+      this.setState({ hasErrors: true, });
       return false;
     }
 
-    let message = this.state.message.trim();
-
     // Sanitize. See: http://shebang.brandonmintern.com/foolproof-html-escaping-in-javascript/
 
     let div = document.createElement('div');
     div.appendChild(document.createTextNode(message));
     message = div.innerHTML;
 
-    if (message) {
-      this.props.handleSendMessage(message);
-    }
-
-    this.setState({ message: '' });
+    return this.props.handleSendMessage(message)
+      .then(() => this.setState({
+        message: '',
+        hasErrors: false,
+      }));
   }
 
   render() {
-    const { intl, chatTitle, chatName, disabled } = this.props;
+    const { intl, chatTitle, chatName, disabled,
+      minMessageLength, maxMessageLength, } = this.props;
+
+    const { hasErrors, error } = this.state;
 
     return (
       <form
         ref="form"
         className={cx(this.props.className, styles.form)}
         onSubmit={this.handleSubmit}>
-        {
-          // <MessageFormActions
-          //   onClick={() => alert('Not supported yet...')}
-          //   className={styles.actions}
-          //   disabled={disabled}
-          //   label={'More actions'}
-          // />
-        }
-        <TextareaAutosize
-          className={styles.input}
-          id="message-input"
-          placeholder={intl.formatMessage(messages.inputPlaceholder, { 0: chatName })}
-          aria-controls={this.props.chatAreaId}
-          aria-label={intl.formatMessage(messages.inputLabel, { 0: chatTitle })}
-          autoCorrect="off"
-          autoComplete="off"
-          spellCheck="true"
-          disabled={disabled}
-          value={this.state.message}
-          onChange={this.handleMessageChange}
-          onKeyDown={this.handleMessageKeyDown}
-        />
-        <Button
-          className={styles.sendButton}
-          aria-label={intl.formatMessage(messages.submitLabel)}
-          type="submit"
-          disabled={disabled}
-          label={intl.formatMessage(messages.submitLabel)}
-          hideLabel={true}
-          icon={'send'}
-          onClick={this.handleMessageKeyDown({ keyCode: 13 })}
-        />
+        <div className={styles.wrapper}>
+          <TextareaAutosize
+            className={styles.input}
+            id="message-input"
+            placeholder={intl.formatMessage(messages.inputPlaceholder, { 0: chatName })}
+            aria-controls={this.props.chatAreaId}
+            aria-label={intl.formatMessage(messages.inputLabel, { 0: chatTitle })}
+            aria-invalid={ hasErrors ? 'true' : 'false' }
+            aria-describedby={ hasErrors ? 'message-input-error' : null }
+            autoCorrect="off"
+            autoComplete="off"
+            spellCheck="true"
+            disabled={disabled}
+            value={this.state.message}
+            onChange={this.handleMessageChange}
+            onKeyDown={this.handleMessageKeyDown}
+          />
+          <Button
+            className={styles.sendButton}
+            aria-label={intl.formatMessage(messages.submitLabel)}
+            type="submit"
+            disabled={disabled}
+            label={intl.formatMessage(messages.submitLabel)}
+            hideLabel={true}
+            icon="send"
+            onClick={() => null}
+          />
+        </div>
+        <div className={styles.info}>
+          { hasErrors ? <span id="message-input-error">{error}</span> : null }
+        </div>
       </form>
     );
   }
diff --git a/bigbluebutton-html5/imports/ui/components/chat/message-form/styles.scss b/bigbluebutton-html5/imports/ui/components/chat/message-form/styles.scss
index a75cdfd355095041e84ca7a8db4d728e932576ba..9fbc08f17b8aa5709df66a27c79dcf90e1027536 100644
--- a/bigbluebutton-html5/imports/ui/components/chat/message-form/styles.scss
+++ b/bigbluebutton-html5/imports/ui/components/chat/message-form/styles.scss
@@ -4,9 +4,14 @@
   flex-grow: 0;
   flex-shrink: 0;
   align-self: flex-end;
+  width: 100%;
+  position: relative;
+  margin-bottom: -$sm-padding-x;
+}
+
+.wrapper {
   display: flex;
   flex-direction: row;
-  width: 100%;
 }
 
 .actions {
@@ -72,3 +77,14 @@
     color: $color-gray-light;
   }
 }
+
+.info {
+  font-size: $font-size-base * .75;
+  color: $color-gray-light;
+  text-align: right;
+  padding: $border-size 0;
+
+  &:before {
+    content: "\00a0"; // non-breaking space
+  }
+}
diff --git a/bigbluebutton-html5/imports/ui/components/chat/service.js b/bigbluebutton-html5/imports/ui/components/chat/service.js
index 4f1a6fe6b54eef79020000c71b1bc5b7b56af85b..603762d9bac912106a6aeb77d944d70cc685a5b8 100644
--- a/bigbluebutton-html5/imports/ui/components/chat/service.js
+++ b/bigbluebutton-html5/imports/ui/components/chat/service.js
@@ -192,9 +192,7 @@ const sendMessage = (receiverID, message) => {
     Storage.setItem(CLOSED_CHAT_LIST_KEY, _.without(currentClosedChats, receiver.id));
   }
 
-  makeCall('sendChat', messagePayload);
-
-  return messagePayload;
+  return makeCall('sendChat', messagePayload);
 };
 
 const getScrollPosition = (receiverID) => {
diff --git a/bigbluebutton-html5/imports/ui/stylesheets/variables/typography.scss b/bigbluebutton-html5/imports/ui/stylesheets/variables/typography.scss
index 4340296f1b03fb0796a4bbe2eacaa451d15d2b87..4cfc353281a56a4cc77a323579839637324d4ed9 100644
--- a/bigbluebutton-html5/imports/ui/stylesheets/variables/typography.scss
+++ b/bigbluebutton-html5/imports/ui/stylesheets/variables/typography.scss
@@ -8,7 +8,7 @@ $font-size-base:          1rem !default;
 $font-size-large:         1.25rem !default;
 $font-size-small:         .875rem !default;
 
-$line-height-base:        1.428571429 !default; // 20/14
+$line-height-base:        1.25 !default; // 20/16
 $line-height-computed:    floor(($font-size-base * $line-height-base)) !default;
 
 $headings-font-family:    inherit !default;
diff --git a/bigbluebutton-html5/private/config/public/chat.yaml b/bigbluebutton-html5/private/config/public/chat.yaml
index 2ae01424b0deffc9b1b12cd6ae89b1d873c276d7..277ff5842daf1d2a7f2fb2b76ee0f354f5e6dc40 100755
--- a/bigbluebutton-html5/private/config/public/chat.yaml
+++ b/bigbluebutton-html5/private/config/public/chat.yaml
@@ -1,5 +1,7 @@
 # Chat service configurations
 chat:
+  min_message_length: 1
+  max_message_length: 5000
   grouping_messages_window: 60000
   # Chat types
   type_system: 'SYSTEM_MESSAGE'
diff --git a/bigbluebutton-html5/private/locales/en.json b/bigbluebutton-html5/private/locales/en.json
index 25ca747596d3e46e643f7fdc4813a21027d3ca96..a2302553931bd505dde2c1663cf79ad336ab5186 100755
--- a/bigbluebutton-html5/private/locales/en.json
+++ b/bigbluebutton-html5/private/locales/en.json
@@ -10,6 +10,8 @@
   "app.chat.submitLabel": "Send Message",
   "app.chat.inputLabel": "Message input for chat {0}",
   "app.chat.inputPlaceholder": "Message {0}",
+  "app.chat.errorMinMessageLength": "The message is {0} characters(s) too short",
+  "app.chat.errorMaxMessageLength": "The message is {0} characters(s) too long",
   "app.chat.titlePublic": "Public Chat",
   "app.chat.titlePrivate": "Private Chat with {0}",
   "app.chat.partnerDisconnected": "{0} has left the meeting",