* Extracts the plain text body from a Gmail message payload. * Prefers text/plain, falls back to text/html with tag stripping.
(part: GmailMessagePart)
| 152 | * Prefers text/plain, falls back to text/html with tag stripping. |
| 153 | */ |
| 154 | function extractBody(part: GmailMessagePart): string { |
| 155 | if (part.mimeType === 'text/plain' && part.body?.data) { |
| 156 | return decodeBase64Url(part.body.data) |
| 157 | } |
| 158 | |
| 159 | if (part.parts) { |
| 160 | // Prefer text/plain from multipart |
| 161 | for (const child of part.parts) { |
| 162 | if (child.mimeType === 'text/plain' && child.body?.data) { |
| 163 | return decodeBase64Url(child.body.data) |
| 164 | } |
| 165 | } |
| 166 | // Fall back to text/html |
| 167 | for (const child of part.parts) { |
| 168 | if (child.mimeType === 'text/html' && child.body?.data) { |
| 169 | return htmlToPlainText(decodeBase64Url(child.body.data)) |
| 170 | } |
| 171 | } |
| 172 | // Recurse into nested multipart |
| 173 | for (const child of part.parts) { |
| 174 | const result = extractBody(child) |
| 175 | if (result) return result |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | if (part.mimeType === 'text/html' && part.body?.data) { |
| 180 | return htmlToPlainText(decodeBase64Url(part.body.data)) |
| 181 | } |
| 182 | |
| 183 | return '' |
| 184 | } |
| 185 | |
| 186 | /** |
| 187 | * Gets a header value from a Gmail message payload. |
no test coverage detected