Attach a file to the message given raw binary data.

        :param data: Raw data to attach to the message.
        :param filename: Name of the file for the data.
        :param content_type: mimetype of the data. It will be guessed from the
            filename if not provided.
        :param content_id: ContentID URL of the attachment.  A RFC 2392-
            compliant URL for the attachment that allows it to be referenced
            from inside the body of the message.  Must start with 'cid:'

def attach_binary(self, data, filename, content_type=None,
                      content_id=None):
        '''Attach a file to the message given raw binary data.

        :param data: Raw data to attach to the message.
        :param filename: Name of the file for the data.
        :param content_type: mimetype of the data. It will be guessed from the
            filename if not provided.
        :param content_id: ContentID URL of the attachment.  A RFC 2392-
            compliant URL for the attachment that allows it to be referenced
            from inside the body of the message.  Must start with 'cid:'
         '''
        if self.attachments is None:
            self.attachments = []
        if content_type is None:
            content_type = self._detect_content_type(filename)
        attachment = {
            'Name': filename,
            'Content': b64encode(data).decode('utf-8'),
            'ContentType': content_type
        }
        if content_id is not None:
            if not content_id.startswith('cid:'):
                raise MessageError('content_id parameter must be an '
                                   'RFC-2392 URL starting with "cid:"')
            attachment['ContentID'] = content_id

        self.attachments.append(attachment)