part.go
func (p *Part) decodeContent(r io.Reader) error {
	// contentReader will point to the end of the content decoding pipeline.
	contentReader := r
	// b64cleaner aggregates errors, must maintain a reference to it to get them later.
	var b64cleaner *coding.Base64Cleaner
	// Build content decoding reader.
	encoding := p.Header.Get(hnContentEncoding)
	validEncoding := true
	switch strings.ToLower(encoding) {
	case cteQuotedPrintable:
		contentReader = coding.NewQPCleaner(contentReader)
		contentReader = quotedprintable.NewReader(contentReader)
	case cteBase64:
		b64cleaner = coding.NewBase64Cleaner(contentReader)
		contentReader = base64.NewDecoder(base64.RawStdEncoding, b64cleaner)
	case cte8Bit, cte7Bit, cteBinary, "":
		// No decoding required.
	default:
		// Unknown encoding.
		validEncoding = false
		p.addWarning(
			ErrorContentEncoding,
			"Unrecognized Content-Transfer-Encoding type %q",
			encoding)
	}
	// Build charset decoding reader.
	if validEncoding && strings.HasPrefix(p.ContentType, "text/") {
		var err error
		contentReader, err = p.convertFromDetectedCharset(contentReader)
		if err != nil {
			return err
		}
	}
	// Decode and store content.
	content, err := ioutil.ReadAll(contentReader)
	if err != nil {
		return errors.WithStack(err)
	}
	p.Content = content
	// Collect base64 errors.
	if b64cleaner != nil {
		for _, err := range b64cleaner.Errors {
			p.Errors = append(p.Errors, &Error{
				Name:   ErrorMalformedBase64,
				Detail: err.Error(),
				Severe: false,
			})
		}
	}
	return nil
}
func (p *Part) decodeContent(r io.Reader) error {
	// contentReader will point to the end of the content decoding pipeline.
	contentReader := r
	// b64cleaner aggregates errors, must maintain a reference to it to get them later.
	var b64cleaner *coding.Base64Cleaner
	// Build content decoding reader.
	encoding := p.Header.Get(hnContentEncoding)
	validEncoding := true
	switch strings.ToLower(encoding) {
	case cteQuotedPrintable:
		contentReader = coding.NewQPCleaner(contentReader)
		contentReader = quotedprintable.NewReader(contentReader)
	case cteBase64:
		b64cleaner = coding.NewBase64Cleaner(contentReader)
		contentReader = base64.NewDecoder(base64.RawStdEncoding, b64cleaner)
	case cte8Bit, cte7Bit, cteBinary, "":
		// No decoding required.
	default:
		// Unknown encoding.
		validEncoding = false
		p.addWarning(
			ErrorContentEncoding,
			"Unrecognized Content-Transfer-Encoding type %q",
			encoding)
	}
	// Build charset decoding reader.
	if validEncoding && strings.HasPrefix(p.ContentType, "text/") {
		var err error
		contentReader, err = p.convertFromDetectedCharset(contentReader)
		if err != nil {
			return err
		}
	}
	// Decode and store content.
	content, err := ioutil.ReadAll(contentReader)
	if err != nil {
		return errors.WithStack(err)
	}
	p.Content = content
	// Collect base64 errors.
	if b64cleaner != nil {
		for _, err := range b64cleaner.Errors {
			p.Errors = append(p.Errors, &Error{
				Name:   ErrorMalformedBase64,
				Detail: err.Error(),
				Severe: false,
			})
		}
	}
	return nil
}
// decodeContent performs transport decoding (base64, quoted-printable) and charset decoding,
// placing the result into Part.Content.  IO errors will be returned immediately; other errors
// and warnings will be added to Part.Errors.