def _convert_message_part_to_str(message_part: email.message.EmailMessage) -> Tuple[str, bool]:
        content: Union[str, bytes] = message_part.get_content()
        content_type = message_part.get_content_type()
        content_transfer_encoding = message_part['Content-Transfer-Encoding']
        logger_dict = {'ContentType': content_type, 'ContentTransferEncoding': content_transfer_encoding}

        if isinstance(content, str):
            logger.info('Successfully decoded message part with {ContentType} {ContentTransferEncoding} as string',
                        fparams=logger_dict)
            return content, False
        try:
            if content_type == 'application/xml':
                decoded_content = content.decode()
                logger.info('Successfully decoded message part with {ContentType} {ContentTransferEncoding} '
                            'as a string', fparams=logger_dict)
                return decoded_content, False
            decoded_content = base64.b64encode(content).decode()
            logger.info('Successfully encoded binary message part with {ContentType} {ContentTransferEncoding} as '
                        'a base64 string', fparams=logger_dict)
            return decoded_content, True
        except UnicodeDecodeError as e:
            logger.error('Failed to decode ebXML message part with {ContentType} {ContentTransferEncoding}.',
                         fparams=logger_dict)
            raise ebxml_envelope.EbXmlParsingError(f'Failed to decode ebXML message part with '
                                                   f'Content-Type: {content_type} and '
                                                   f'Content-Transfer-Encoding: {content_transfer_encoding}') from e
    def _extract_message_parts(msg: email.message.EmailMessage) -> Tuple[str, str, List[Dict[str, Union[str, bool]]]]:
        """Extract the ebXML and payload parts of the message and return them as a tuple.

        :param msg: The message to extract parts from.
        :return: A tuple containing the ebXML and payload (if present, otherwise None) parts of the message provided.
        """
        # EIS section 2.5.4 defines that the first MIME part must contain the ebML SOAP message and the message payload
        # (if present) must be the first additional attachment.

        if not msg.is_multipart():
            logger.error('Non-multipart message received')
            raise ebxml_envelope.EbXmlParsingError("Non-multipart message received")

        message_parts: Sequence[email.message.EmailMessage] = tuple(msg.iter_parts())

        EbxmlRequestEnvelope._report_any_defects_in_message_parts(message_parts)

        # ebXML part is the first part of the message
        ebxml_part = EbxmlRequestEnvelope._extract_ebxml_part(message_parts[0])

        payload_part = None
        attachments = []
        if len(message_parts) > 1:
            # HL7 payload part is the second part of the message
            payload_part = EbxmlRequestEnvelope._extract_hl7_payload_part(message_parts[1])

            # Any additional attachments are from the third part of the message onwards
            attachments.extend(EbxmlRequestEnvelope._extract_additional_attachments_parts(message_parts[2:]))

        return ebxml_part, payload_part, attachments
 def _extract_hl7_payload_part(
         message_part: email.message.EmailMessage) -> str:
     payload_part, is_base64_payload = EbxmlRequestEnvelope._convert_message_part_to_str(
         message_part)
     if is_base64_payload:
         logger.error(
             '0008', 'Failed to decode HL7 payload part of message as text')
         raise ebxml_envelope.EbXmlParsingError(
             "Failed to decode HL7 payload part of message as text")
     return payload_part
 def _extract_ebxml_part(message_part: email.message.EmailMessage) -> str:
     ebxml_part, is_base64_ebxml_part = EbxmlRequestEnvelope._convert_message_part_to_str(
         message_part)
     if is_base64_ebxml_part:
         logger.error(
             '0007',
             'Failed to decode ebXML header part of message as text')
         raise ebxml_envelope.EbXmlParsingError(
             "Failed to decode ebXML header part of message as text")
     return ebxml_part