instructure/canvas-lms · error

Unrecognized Content-Type: #

Error message

Unrecognized Content-Type: #{incoming_message.mime_type.inspect}

What it means

IncomingMessageProcessor#extract_body only understands text/plain, text/html, or a nil MIME type on incoming messages. Any other Content-Type (e.g. multipart variants, images, or exotic types surfacing from misparsed mail) has no extraction path and raises so the message can be handled by error processing instead of producing an empty body.

Solutions

  1. Inspect the offending message's Content-Type header to confirm why it isn't text/plain or text/html.
  2. Ensure the mail library (Mail gem) fully parses multipart messages so extract_body receives a leaf part, not the multipart container.
  3. Fix malformed MIME boundaries upstream or reject/skip such messages in process_single error handling.
  4. If a new legitimate type must be supported, extend the case statement to map it (e.g. decode HTML branch for multipart/related leaf parts).

Example fix

// before
# raise "Unrecognized Content-Type: multipart/related"
// after (in code that feeds extract_body)
parts = incoming_message.multipart? ? incoming_message.text_part : incoming_message
raise ArgumentError, 'no text part' if parts.nil?
extract_body(parts)
Defensive patterns

Strategy: try-catch

Validate before calling

mime = incoming_message.mime_type
return :unsupported unless mime.nil? || %w[text/plain text/html].include?(mime)

Type guard

def supported_mime?(msg)
  msg.mime_type.nil? || %w[text/plain text/html].include?(msg.mime_type)
end

Try / catch

begin
  processor.process_single(message)
rescue RuntimeError => e
  raise unless e.message.start_with?('Unrecognized Content-Type:')
  mailbox.move_file(message.id, :failure) # route to failure folder for inspection
end

Prevention

When it happens

Trigger: Processing an inbound email whose top-level MIME type is neither text/plain nor text/html — commonly multipart/* that the mail library did not decompose, or messages with attachments as the primary part, messages with content types like application/* forwarded whole.

Common situations: Non-English mail clients emitting odd content types; emails where the parser fails to split multipart (malformed MIME boundaries); forwarded message/rfc822 bodies; HTML-only newsletters parsed as multipart/related without a text part handled upstream.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/c6820aeab287824a. Report an issue: GitHub.

Appendix: source

Thrown at gems/incoming_mail_processor/lib/incoming_mail_processor/incoming_message_processor.rb:265

    end

    private

    def extract_body(incoming_message)
      if incoming_message.multipart?
        html_part = incoming_message.html_part
        text_part = incoming_message.text_part

        html_body = self.class.utf8ify(html_part.body.decoded, html_part.charset) if html_part
        text_body = self.class.utf8ify(text_part.body.decoded, text_part.charset) if text_part
      else
        case incoming_message.mime_type
        when "text/plain", nil
          text_body = self.class.utf8ify(incoming_message.body.decoded, incoming_message.charset)
        when "text/html"
          html_body = self.class.utf8ify(incoming_message.body.decoded, incoming_message.charset)
        else
          raise "Unrecognized Content-Type: #{incoming_message.mime_type.inspect}"
        end
      end

      if html_body && !text_body
        text_body = self.class.html_to_text(html_body)
      end

      if text_body && !html_body
        html_body = self.class.format_message(text_body).first
      end

      [text_body, html_body]
    end

    def report_stats(incoming_message, mailbox_account)
      InstStatsd::Statsd.distributed_increment("incoming_mail_processor.incoming_message_processed.#{mailbox_account.escaped_address}",
                                               short_stat: "incoming_mail_processor.incoming_message_processed",
                                               tags: { mailbox: mailbox_account.escaped_address })

View on GitHub (pinned to 1c9f0bb801)