part.go
func (p *Part) convertFromDetectedCharset(r io.Reader) (io.Reader, error) {
	// Attempt to detect character set from part content.
	var cd *chardet.Detector
	switch p.ContentType {
	case "text/html":
		cd = chardet.NewHtmlDetector()
	default:
		cd = chardet.NewTextDetector()
	}

	buf, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	cs, err := cd.DetectBest(buf)
	switch err {
	case nil:
		// Carry on
	case chardet.NotDetectedError:
		p.addWarning(ErrorCharsetDeclaration, "charset could not be detected: %v", err)
	default:
		return nil, errors.WithStack(err)
	}

	// Restore r.
	r = bytes.NewReader(buf)

	if cs == nil || cs.Confidence < minCharsetConfidence {
		// Low confidence, use declared character set.
		return p.convertFromStatedCharset(r), nil
	}

	// Confidence exceeded our threshold, use detected character set.
	if p.Charset != "" && !strings.EqualFold(cs.Charset, p.Charset) {
		p.addWarning(ErrorCharsetDeclaration,
			"declared charset %q, detected %q, confidence %d",
			p.Charset, cs.Charset, cs.Confidence)
	}

	reader, err := coding.NewCharsetReader(cs.Charset, r)
	if err != nil {
		// Failed to get a conversion reader.
		p.addWarning(ErrorCharsetConversion, err.Error())
	} else {
		r = reader
		p.OrigCharset = p.Charset
		p.Charset = cs.Charset
	}

	return r, nil
}
func (p *Part) convertFromDetectedCharset(r io.Reader) (io.Reader, error) {
	// Attempt to detect character set from part content.
	var cd *chardet.Detector
	switch p.ContentType {
	case "text/html":
		cd = chardet.NewHtmlDetector()
	default:
		cd = chardet.NewTextDetector()
	}

	buf, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	cs, err := cd.DetectBest(buf)
	switch err {
	case nil:
		// Carry on
	case chardet.NotDetectedError:
		p.addWarning(ErrorCharsetDeclaration, "charset could not be detected: %v", err)
	default:
		return nil, errors.WithStack(err)
	}

	// Restore r.
	r = bytes.NewReader(buf)

	if cs == nil || cs.Confidence < minCharsetConfidence {
		// Low confidence, use declared character set.
		return p.convertFromStatedCharset(r), nil
	}

	// Confidence exceeded our threshold, use detected character set.
	if p.Charset != "" && !strings.EqualFold(cs.Charset, p.Charset) {
		p.addWarning(ErrorCharsetDeclaration,
			"declared charset %q, detected %q, confidence %d",
			p.Charset, cs.Charset, cs.Confidence)
	}

	reader, err := coding.NewCharsetReader(cs.Charset, r)
	if err != nil {
		// Failed to get a conversion reader.
		p.addWarning(ErrorCharsetConversion, err.Error())
	} else {
		r = reader
		p.OrigCharset = p.Charset
		p.Charset = cs.Charset
	}

	return r, nil
}
// convertFromDetectedCharset attempts to detect the character set for the given part, and returns
// an io.Reader that will convert from that charset to UTF-8. If the charset cannot be detected,
// this method adds a warning to the part and automatically falls back to using
// `convertFromStatedCharset` and returns the reader from that method.