@mavogel/awscdk-rootmail 0.1.24 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +9 -9
- package/lib/rootmail.js +1 -1
- package/lib/ses-receive.js +1 -1
- package/lib/ses-receive.ops-santa-handler.js +2 -2
- package/node_modules/@aws-sdk/checksums/package.json +3 -3
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-cjs/index.js +9 -7
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-es/schemas/schemas_0.js +11 -6
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/DescribeDeliveriesCommand.d.ts +3 -0
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/DescribeDeliveryDestinationsCommand.d.ts +3 -0
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/DescribeDeliverySourcesCommand.d.ts +3 -0
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/PutResourcePolicyCommand.d.ts +1 -1
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/models/models_0.d.ts +27 -1
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/ts3.4/models/models_0.d.ts +3 -0
- package/node_modules/@aws-sdk/client-cloudwatch-logs/package.json +4 -4
- package/node_modules/@aws-sdk/client-route-53/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-route-53/package.json +4 -4
- package/node_modules/@aws-sdk/client-s3/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-s3/package.json +7 -7
- package/node_modules/@aws-sdk/client-ses/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-ses/package.json +4 -4
- package/node_modules/@aws-sdk/client-ssm/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-ssm/package.json +4 -4
- package/node_modules/@aws-sdk/core/dist-cjs/submodules/protocols/index.js +94 -1589
- package/node_modules/@aws-sdk/core/dist-es/submodules/protocols/index.js +1 -7
- package/node_modules/@aws-sdk/core/dist-es/submodules/protocols/json/AwsJsonRpcProtocol.js +1 -3
- package/node_modules/@aws-sdk/core/dist-es/submodules/protocols/json/AwsRestJsonProtocol.js +1 -3
- package/node_modules/@aws-sdk/core/dist-types/submodules/protocols/index.d.ts +2 -8
- package/node_modules/@aws-sdk/core/dist-types/submodules/protocols/json/AwsJson1_0Protocol.d.ts +1 -2
- package/node_modules/@aws-sdk/core/dist-types/submodules/protocols/json/AwsJson1_1Protocol.d.ts +1 -2
- package/node_modules/@aws-sdk/core/dist-types/submodules/protocols/json/AwsJsonRpcProtocol.d.ts +2 -3
- package/node_modules/@aws-sdk/core/dist-types/submodules/protocols/json/AwsRestJsonProtocol.d.ts +2 -3
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/index.d.ts +10 -10
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/json/AwsJson1_0Protocol.d.ts +1 -2
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/json/AwsJson1_1Protocol.d.ts +1 -2
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/json/AwsJsonRpcProtocol.d.ts +2 -3
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/json/AwsRestJsonProtocol.d.ts +2 -3
- package/node_modules/@aws-sdk/core/package.json +2 -2
- package/node_modules/@aws-sdk/credential-provider-env/package.json +3 -3
- package/node_modules/@aws-sdk/credential-provider-http/package.json +3 -3
- package/node_modules/@aws-sdk/credential-provider-ini/package.json +10 -10
- package/node_modules/@aws-sdk/credential-provider-login/package.json +4 -4
- package/node_modules/@aws-sdk/credential-provider-node/package.json +8 -8
- package/node_modules/@aws-sdk/credential-provider-process/package.json +3 -3
- package/node_modules/@aws-sdk/credential-provider-sso/package.json +5 -5
- package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +4 -4
- package/node_modules/@aws-sdk/middleware-sdk-s3/package.json +3 -3
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/cognito-identity/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/signin/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso-oidc/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sts/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/package.json +3 -3
- package/node_modules/@aws-sdk/token-providers/dist-cjs/index.js +37 -19
- package/node_modules/@aws-sdk/token-providers/dist-es/fromSso.js +37 -19
- package/node_modules/@aws-sdk/token-providers/package.json +4 -4
- package/node_modules/@smithy/core/dist-cjs/submodules/protocols/index.js +1695 -3
- package/node_modules/@smithy/core/dist-es/submodules/protocols/ConfigurableSerdeContext.js +6 -0
- package/node_modules/@smithy/core/dist-es/submodules/protocols/UnionSerde.js +26 -0
- package/node_modules/@smithy/core/dist-es/submodules/protocols/common.js +3 -0
- package/node_modules/@smithy/core/dist-es/submodules/protocols/index.js +8 -0
- package/node_modules/@smithy/core/dist-es/submodules/protocols/json/SmithyRpcV2JsonProtocol.js +102 -0
- package/node_modules/{@aws-sdk → @smithy}/core/dist-es/submodules/protocols/json/codec-v1/JsonShapeDeserializer.js +8 -1
- package/node_modules/{@aws-sdk → @smithy}/core/dist-es/submodules/protocols/json/codec-v1/JsonShapeSerializer.js +8 -1
- package/node_modules/{@aws-sdk → @smithy}/core/dist-es/submodules/protocols/json/codec-v2/JsonShapeDeserializer2.js +13 -2
- package/node_modules/{@aws-sdk → @smithy}/core/dist-es/submodules/protocols/json/codec-v2/JsonShapeSerializer2.js +11 -1
- package/node_modules/{@aws-sdk → @smithy}/core/dist-es/submodules/protocols/json/parseJsonBody.js +16 -1
- package/node_modules/@smithy/core/dist-es/submodules/protocols/writeKey.js +3 -0
- package/node_modules/@smithy/core/dist-types/submodules/protocols/ConfigurableSerdeContext.d.ts +8 -0
- package/node_modules/@smithy/core/dist-types/submodules/protocols/UnionSerde.d.ts +24 -0
- package/node_modules/@smithy/core/dist-types/submodules/protocols/common.d.ts +2 -0
- package/node_modules/@smithy/core/dist-types/submodules/protocols/index.d.ts +9 -0
- package/node_modules/@smithy/core/dist-types/submodules/protocols/json/JsonSettings.d.ts +13 -0
- package/node_modules/@smithy/core/dist-types/submodules/protocols/json/SmithyRpcV2JsonProtocol.d.ts +28 -0
- package/node_modules/{@aws-sdk → @smithy}/core/dist-types/submodules/protocols/json/parseJsonBody.d.ts +16 -0
- package/node_modules/@smithy/core/dist-types/submodules/protocols/writeKey.d.ts +4 -0
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/ConfigurableSerdeContext.d.ts +8 -0
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/UnionSerde.d.ts +24 -0
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/common.d.ts +2 -0
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/index.d.ts +9 -0
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/json/JsonSettings.d.ts +13 -0
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/json/SmithyRpcV2JsonProtocol.d.ts +28 -0
- package/node_modules/{@aws-sdk → @smithy}/core/dist-types/ts3.4/submodules/protocols/json/codec-v1/JsonCodec.d.ts +15 -11
- package/node_modules/{@aws-sdk/core/dist-types/ts3.4/submodules/protocols/json → @smithy/core/dist-types/ts3.4/submodules/protocols/json/codec-v1}/JsonSettings.d.ts +7 -4
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/json/codec-v1/JsonShapeDeserializer.d.ts +14 -0
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/json/codec-v1/JsonShapeSerializer.d.ts +29 -0
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/json/codec-v2/JsonBytesStringAdapter.d.ts +51 -0
- package/node_modules/{@aws-sdk → @smithy}/core/dist-types/ts3.4/submodules/protocols/json/codec-v2/JsonCodec2.d.ts +13 -9
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/json/codec-v2/JsonShapeDeserializer2.d.ts +30 -0
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/json/codec-v2/JsonShapeSerializer2.d.ts +60 -0
- package/node_modules/{@aws-sdk → @smithy}/core/dist-types/ts3.4/submodules/protocols/json/detectBufferParsing.d.ts +1 -1
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/json/jsonReplacer.d.ts +21 -0
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/json/jsonReviver.d.ts +15 -0
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/json/needsReviver.d.ts +11 -0
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/json/parseJsonBody.d.ts +38 -0
- package/node_modules/@smithy/core/dist-types/ts3.4/submodules/protocols/writeKey.d.ts +4 -0
- package/node_modules/@smithy/core/package.json +2 -1
- package/node_modules/@zone-eu/mailsplit/README.md +43 -54
- package/node_modules/@zone-eu/mailsplit/lib/headers.js +10 -4
- package/node_modules/@zone-eu/mailsplit/lib/message-splitter.js +5 -4
- package/node_modules/@zone-eu/mailsplit/lib/mime-node.d.ts +4 -1
- package/node_modules/@zone-eu/mailsplit/lib/mime-node.js +30 -5
- package/node_modules/@zone-eu/mailsplit/lib/types.d.ts +3 -1
- package/node_modules/@zone-eu/mailsplit/package.json +22 -17
- package/node_modules/libbase64/CHANGELOG.md +20 -0
- package/node_modules/libbase64/README.md +40 -13
- package/node_modules/libbase64/dist/cjs/libbase64.d.ts +80 -0
- package/node_modules/libbase64/dist/cjs/libbase64.js +310 -0
- package/node_modules/libbase64/dist/cjs/package.json +3 -0
- package/node_modules/libbase64/dist/esm/libbase64.d.ts +80 -0
- package/node_modules/libbase64/{lib → dist/esm}/libbase64.js +74 -117
- package/node_modules/libbase64/dist/esm/package.json +3 -0
- package/node_modules/libbase64/package.json +59 -13
- package/node_modules/libmime/CHANGELOG.md +38 -0
- package/node_modules/libmime/README.md +55 -26
- package/node_modules/libmime/SECURITY.md +152 -0
- package/node_modules/libmime/dist/cjs/charset.d.ts +43 -0
- package/node_modules/libmime/dist/cjs/charset.js +135 -0
- package/node_modules/libmime/dist/cjs/charsets.d.ts +2 -0
- package/node_modules/libmime/dist/cjs/charsets.js +213 -0
- package/node_modules/libmime/dist/cjs/get-charset-name.d.ts +1 -0
- package/node_modules/libmime/dist/cjs/get-charset-name.js +224 -0
- package/node_modules/libmime/dist/cjs/libmime.d.ts +218 -0
- package/node_modules/libmime/dist/cjs/libmime.js +1027 -0
- package/node_modules/libmime/dist/cjs/mimetypes.d.ts +7 -0
- package/node_modules/libmime/dist/cjs/mimetypes.js +2072 -0
- package/node_modules/libmime/dist/cjs/package.json +3 -0
- package/node_modules/libmime/dist/cjs/types.d.ts +59 -0
- package/node_modules/libmime/dist/cjs/types.js +4 -0
- package/node_modules/libmime/dist/esm/charset.d.ts +43 -0
- package/node_modules/libmime/dist/esm/charset.js +125 -0
- package/node_modules/libmime/dist/esm/charsets.d.ts +2 -0
- package/node_modules/libmime/{lib → dist/esm}/charsets.js +3 -5
- package/node_modules/libmime/dist/esm/get-charset-name.d.ts +1 -0
- package/node_modules/libmime/{lib → dist/esm}/get-charset-name.js +1 -8
- package/node_modules/libmime/dist/esm/libmime.d.ts +219 -0
- package/node_modules/libmime/{lib → dist/esm}/libmime.js +275 -334
- package/node_modules/libmime/dist/esm/mimetypes.d.ts +7 -0
- package/node_modules/libmime/dist/esm/mimetypes.js +2068 -0
- package/node_modules/libmime/dist/esm/package.json +3 -0
- package/node_modules/libmime/dist/esm/types.d.ts +59 -0
- package/node_modules/libmime/dist/esm/types.js +3 -0
- package/node_modules/libmime/package.json +60 -15
- package/node_modules/libqp/CHANGELOG.md +18 -0
- package/node_modules/libqp/README.md +50 -19
- package/node_modules/libqp/dist/cjs/libqp.d.ts +74 -0
- package/node_modules/libqp/dist/cjs/libqp.js +378 -0
- package/node_modules/libqp/dist/cjs/package.json +3 -0
- package/node_modules/libqp/dist/esm/libqp.d.ts +74 -0
- package/node_modules/libqp/dist/esm/libqp.js +369 -0
- package/node_modules/libqp/dist/esm/package.json +3 -0
- package/node_modules/libqp/lib/libqp.js +4 -383
- package/node_modules/libqp/lib/package.json +3 -0
- package/node_modules/libqp/package.json +62 -6
- package/node_modules/mailparser/CHANGELOG.md +56 -0
- package/node_modules/mailparser/README.md +6 -0
- package/node_modules/mailparser/dist/cjs/index.d.ts +10 -0
- package/node_modules/mailparser/dist/cjs/index.js +12 -0
- package/node_modules/mailparser/dist/cjs/mail-parser.d.ts +98 -0
- package/node_modules/mailparser/dist/cjs/mail-parser.js +1419 -0
- package/node_modules/mailparser/dist/cjs/package.json +3 -0
- package/node_modules/mailparser/dist/cjs/simple-parser.d.ts +17 -0
- package/node_modules/mailparser/dist/cjs/simple-parser.js +133 -0
- package/node_modules/mailparser/dist/cjs/stream-hash.d.ts +24 -0
- package/node_modules/mailparser/dist/cjs/stream-hash.js +33 -0
- package/node_modules/mailparser/dist/cjs/tlds.cjs +8 -0
- package/node_modules/mailparser/dist/cjs/types.d.ts +309 -0
- package/node_modules/mailparser/dist/cjs/types.js +2 -0
- package/node_modules/mailparser/dist/esm/index.d.ts +10 -0
- package/node_modules/mailparser/dist/esm/index.js +4 -0
- package/node_modules/mailparser/dist/esm/mail-parser.d.ts +98 -0
- package/node_modules/mailparser/{lib → dist/esm}/mail-parser.js +302 -368
- package/node_modules/mailparser/dist/esm/package.json +3 -0
- package/node_modules/mailparser/dist/esm/simple-parser.d.ts +17 -0
- package/node_modules/mailparser/{lib → dist/esm}/simple-parser.js +45 -68
- package/node_modules/mailparser/dist/esm/stream-hash.d.ts +24 -0
- package/node_modules/mailparser/{lib → dist/esm}/stream-hash.js +7 -9
- package/node_modules/mailparser/dist/esm/tlds.cjs +8 -0
- package/node_modules/mailparser/dist/esm/types.d.ts +309 -0
- package/node_modules/mailparser/dist/esm/types.js +1 -0
- package/node_modules/mailparser/package.json +88 -17
- package/node_modules/nodemailer/CHANGELOG.md +44 -0
- package/node_modules/nodemailer/dist/cjs/addressparser/index.js +695 -267
- package/node_modules/nodemailer/dist/cjs/mailer/mail-message.js +4 -1
- package/node_modules/nodemailer/dist/cjs/mime-funcs/index.js +8 -2
- package/node_modules/nodemailer/dist/cjs/mime-node/index.js +48 -16
- package/node_modules/nodemailer/dist/cjs/package-info.d.ts +1 -1
- package/node_modules/nodemailer/dist/cjs/package-info.js +1 -1
- package/node_modules/nodemailer/dist/cjs/shared/url.js +22 -5
- package/node_modules/nodemailer/dist/esm/addressparser/index.js +695 -267
- package/node_modules/nodemailer/dist/esm/mailer/mail-message.js +4 -1
- package/node_modules/nodemailer/dist/esm/mime-funcs/index.js +8 -2
- package/node_modules/nodemailer/dist/esm/mime-node/index.js +48 -16
- package/node_modules/nodemailer/dist/esm/package-info.d.ts +1 -1
- package/node_modules/nodemailer/dist/esm/package-info.js +1 -1
- package/node_modules/nodemailer/dist/esm/shared/url.js +22 -5
- package/node_modules/nodemailer/package.json +1 -1
- package/package.json +9 -9
- package/node_modules/@aws-sdk/core/dist-types/submodules/protocols/json/codec-v1/JsonSettings.d.ts +0 -7
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/json/codec-v1/JsonSettings.d.ts +0 -4
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/json/codec-v1/JsonShapeDeserializer.d.ts +0 -13
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/json/codec-v1/JsonShapeSerializer.d.ts +0 -18
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/json/codec-v2/JsonBytesStringAdapter.d.ts +0 -27
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/json/codec-v2/JsonShapeDeserializer2.d.ts +0 -15
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/json/codec-v2/JsonShapeSerializer2.d.ts +0 -39
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/json/jsonReplacer.d.ts +0 -7
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/json/jsonReviver.d.ts +0 -7
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/json/needsReviver.d.ts +0 -2
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/json/parseJsonBody.d.ts +0 -14
- package/node_modules/libbase64/.eslintrc +0 -11
- package/node_modules/libbase64/.github/FUNDING.yml +0 -4
- package/node_modules/libbase64/.github/VULNERABILITY_REPORT.yml +0 -75
- package/node_modules/libbase64/.github/workflows/release.yaml +0 -39
- package/node_modules/libbase64/.github/workflows/test.yml +0 -21
- package/node_modules/libbase64/.ncurc.js +0 -13
- package/node_modules/libbase64/.prettierrc.js +0 -8
- package/node_modules/libmime/lib/charset.js +0 -131
- package/node_modules/libmime/lib/mimetypes.js +0 -2049
- package/node_modules/libqp/.eslintrc +0 -15
- package/node_modules/libqp/.github/FUNDING.yml +0 -4
- package/node_modules/libqp/.github/VULNERABILITY_REPORT.yml +0 -75
- package/node_modules/libqp/.github/workflows/release.yaml +0 -39
- package/node_modules/libqp/.github/workflows/test.yml +0 -21
- package/node_modules/libqp/.prettierrc.js +0 -8
- package/node_modules/libqp/test/libqp-test.js +0 -366
- package/node_modules/mailparser/.gitattributes +0 -1
- package/node_modules/mailparser/.prettierignore +0 -3
- package/node_modules/mailparser/.prettierrc.js +0 -10
- package/node_modules/mailparser/.release-please-manifest.json +0 -3
- package/node_modules/mailparser/eslint.config.js +0 -33
- package/node_modules/mailparser/index.js +0 -9
- package/node_modules/mailparser/release-please-config.json +0 -10
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-es/submodules/protocols/json/JsonSettings.js +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-es/submodules/protocols/json/codec-v1/JsonCodec.js +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-es/submodules/protocols/json/codec-v1/JsonSettings.js +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-es/submodules/protocols/json/codec-v2/JsonBytesStringAdapter.js +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-es/submodules/protocols/json/codec-v2/JsonCodec2.js +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-es/submodules/protocols/json/detectBufferParsing.js +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-es/submodules/protocols/json/jsonReplacer.js +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-es/submodules/protocols/json/jsonReviver.js +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-es/submodules/protocols/json/needsReviver.js +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-types/submodules/protocols/json/codec-v1/JsonCodec.d.ts +0 -0
- /package/node_modules/{@aws-sdk/core/dist-types/submodules/protocols/json → @smithy/core/dist-types/submodules/protocols/json/codec-v1}/JsonSettings.d.ts +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-types/submodules/protocols/json/codec-v1/JsonShapeDeserializer.d.ts +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-types/submodules/protocols/json/codec-v1/JsonShapeSerializer.d.ts +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-types/submodules/protocols/json/codec-v2/JsonBytesStringAdapter.d.ts +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-types/submodules/protocols/json/codec-v2/JsonCodec2.d.ts +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-types/submodules/protocols/json/codec-v2/JsonShapeDeserializer2.d.ts +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-types/submodules/protocols/json/codec-v2/JsonShapeSerializer2.d.ts +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-types/submodules/protocols/json/detectBufferParsing.d.ts +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-types/submodules/protocols/json/jsonReplacer.d.ts +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-types/submodules/protocols/json/jsonReviver.d.ts +0 -0
- /package/node_modules/{@aws-sdk → @smithy}/core/dist-types/submodules/protocols/json/needsReviver.d.ts +0 -0
|
@@ -1,21 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
const linkify = require('linkify-it')();
|
|
16
|
-
const tlds = require('tlds');
|
|
17
|
-
const encodingJapanese = require('encoding-japanese');
|
|
18
|
-
|
|
1
|
+
import mailsplit from '@zone-eu/mailsplit';
|
|
2
|
+
import FlowedDecoder from '@zone-eu/mailsplit/lib/flowed-decoder.js';
|
|
3
|
+
import encodingJapanese from 'encoding-japanese';
|
|
4
|
+
import he from 'he';
|
|
5
|
+
import { htmlToText } from 'html-to-text';
|
|
6
|
+
import iconv from 'iconv-lite';
|
|
7
|
+
import libmime from 'libmime';
|
|
8
|
+
import linkifyIt from 'linkify-it';
|
|
9
|
+
import addressparser from 'nodemailer/lib/addressparser';
|
|
10
|
+
import punycode from 'punycode.js';
|
|
11
|
+
import { Transform } from 'node:stream';
|
|
12
|
+
import tlds from './tlds.cjs';
|
|
13
|
+
import StreamHash from './stream-hash.js';
|
|
14
|
+
const { Splitter, ChunkedPassthrough } = mailsplit;
|
|
19
15
|
// Bounds for link detection in text bodies. Message content is untrusted and
|
|
20
16
|
// linkify-it backtracks heavily on crafted input: matching a host is quadratic
|
|
21
17
|
// in the length of a single whitespace-free run and exponential in the number
|
|
@@ -33,37 +29,32 @@ const encodingJapanese = require('encoding-japanese');
|
|
|
33
29
|
const MAX_LINKIFY_SEGMENT_LENGTH = 4096;
|
|
34
30
|
const MAX_LINKIFY_HOST_LABELS = 6;
|
|
35
31
|
const MAX_LINKIFY_WORK = 768 * 1024 * 1024; // shared by all text parts of a message
|
|
36
|
-
|
|
37
32
|
// Default upper bound for the total length of the URLs updateImageLinks() writes
|
|
38
33
|
// into the HTML (options.maxInlinedImagesSize). simpleParser inlines every cid:
|
|
39
34
|
// reference as a full data: URL, so a small message repeating a reference to
|
|
40
35
|
// one image thousands of times would otherwise grow the HTML past the maximum
|
|
41
36
|
// string length. References beyond the budget are left as cid: links.
|
|
42
37
|
const MAX_INLINED_IMAGES_SIZE = 20 * 1024 * 1024;
|
|
43
|
-
|
|
44
38
|
// List-* header names that must not become keys of the plain list object
|
|
45
39
|
const UNSAFE_LIST_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
46
|
-
|
|
40
|
+
const linkify = linkifyIt();
|
|
47
41
|
linkify
|
|
48
42
|
.tlds(tlds) // Reload with full tlds list
|
|
49
43
|
.tlds('onion', true) // Add unofficial `.onion` domain
|
|
50
44
|
.add('git:', 'http:') // Add `git:` ptotocol as "alias"
|
|
51
45
|
.add('ftp:', null) // Disable `ftp:` ptotocol
|
|
52
46
|
.set({ fuzzyIP: true, fuzzyLink: true, fuzzyEmail: true });
|
|
53
|
-
|
|
54
47
|
// Characters linkify-it accepts inside a host name: letters, digits, a dash,
|
|
55
48
|
// and anything non-ASCII (its label pattern takes any character that is not
|
|
56
49
|
// punctuation, whitespace or a control character).
|
|
57
50
|
function isHostChar(code) {
|
|
58
51
|
return (code >= 0x61 && code <= 0x7a) || (code >= 0x41 && code <= 0x5a) || (code >= 0x30 && code <= 0x39) || code === 0x2d || code >= 0x80;
|
|
59
52
|
}
|
|
60
|
-
|
|
61
53
|
// twitter linkifier from
|
|
62
54
|
// https://github.com/markdown-it/linkify-it#example-2-add-twitter-mentions-handler
|
|
63
55
|
linkify.add('@', {
|
|
64
56
|
validate(text, pos, self) {
|
|
65
57
|
let tail = text.slice(pos);
|
|
66
|
-
|
|
67
58
|
if (!self.re.twitter) {
|
|
68
59
|
self.re.twitter = new RegExp('^([a-zA-Z0-9_]){1,15}(?!_)(?=$|' + self.re.src_ZPCc + ')');
|
|
69
60
|
}
|
|
@@ -81,7 +72,6 @@ linkify.add('@', {
|
|
|
81
72
|
match.url = 'https://twitter.com/' + match.url.replace(/^@/, '');
|
|
82
73
|
}
|
|
83
74
|
});
|
|
84
|
-
|
|
85
75
|
// Lists the parameters a header value gives in RFC 2231 form (name*=, name*0= or
|
|
86
76
|
// name*0*=). libmime decodes those while parsing the header, so the result must not go
|
|
87
77
|
// through decodeWords as well: filename*=utf-8''a%3D%3Futf-8%3FQ%3F%3D2Eexe%3F%3D would
|
|
@@ -91,8 +81,7 @@ function rfc2231ParamNames(value) {
|
|
|
91
81
|
let quote = false;
|
|
92
82
|
let escaped = false;
|
|
93
83
|
let start = 0;
|
|
94
|
-
|
|
95
|
-
let addSegment = end => {
|
|
84
|
+
let addSegment = (end) => {
|
|
96
85
|
let segment = value.substring(start, end);
|
|
97
86
|
let eq = segment.indexOf('=');
|
|
98
87
|
if (eq < 0) {
|
|
@@ -107,46 +96,40 @@ function rfc2231ParamNames(value) {
|
|
|
107
96
|
names.add(match[1]);
|
|
108
97
|
}
|
|
109
98
|
};
|
|
110
|
-
|
|
111
99
|
for (let i = 0; i < value.length; i++) {
|
|
112
100
|
let chr = value.charAt(i);
|
|
113
101
|
if (escaped) {
|
|
114
102
|
escaped = false;
|
|
115
|
-
}
|
|
103
|
+
}
|
|
104
|
+
else if (chr === '\\') {
|
|
116
105
|
escaped = true;
|
|
117
|
-
}
|
|
106
|
+
}
|
|
107
|
+
else if (chr === '"') {
|
|
118
108
|
quote = !quote;
|
|
119
|
-
}
|
|
109
|
+
}
|
|
110
|
+
else if (chr === ';' && !quote) {
|
|
120
111
|
addSegment(i);
|
|
121
112
|
start = i + 1;
|
|
122
113
|
}
|
|
123
114
|
}
|
|
124
115
|
addSegment(value.length);
|
|
125
|
-
|
|
126
116
|
return names;
|
|
127
117
|
}
|
|
128
|
-
|
|
129
118
|
// Deepest element nesting html-to-text is asked to convert. htmlparser2 keeps its open
|
|
130
119
|
// element stack at the front of an array, so parsing alone is quadratic in the nesting
|
|
131
120
|
// depth (200k nested <b> took 9 s), and html-to-text's recursive walk overflows the call
|
|
132
121
|
// stack at about 2000 levels. Real markup stays far below this: Chrome's own parser
|
|
133
122
|
// flattens anything nested deeper than 512 levels.
|
|
134
123
|
const MAX_HTML_NESTING_DEPTH = 1000;
|
|
135
|
-
|
|
136
124
|
// Elements that never hold content, so a start tag does not open a level
|
|
137
125
|
const HTML_VOID_ELEMENTS = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']);
|
|
138
|
-
|
|
139
126
|
// Elements the HTML parser closes implicitly when a sibling opens (li after li, td after
|
|
140
127
|
// td, p after p), so an unclosed run of them does not nest. They are left out of the depth
|
|
141
128
|
// count: a report with thousands of unclosed table cells is sloppy but common markup
|
|
142
129
|
const HTML_IMPLIED_END_ELEMENTS = new Set(['p', 'li', 'dt', 'dd', 'option', 'optgroup', 'tr', 'td', 'th', 'thead', 'tbody', 'tfoot', 'rt', 'rp']);
|
|
143
|
-
|
|
144
130
|
function isTagNameChar(code) {
|
|
145
|
-
return (
|
|
146
|
-
(code >= 0x61 && code <= 0x7a) || (code >= 0x41 && code <= 0x5a) || (code >= 0x30 && code <= 0x39) || code === 0x2d || code === 0x3a || code === 0x5f
|
|
147
|
-
);
|
|
131
|
+
return ((code >= 0x61 && code <= 0x7a) || (code >= 0x41 && code <= 0x5a) || (code >= 0x30 && code <= 0x39) || code === 0x2d || code === 0x3a || code === 0x5f);
|
|
148
132
|
}
|
|
149
|
-
|
|
150
133
|
// Reports whether `html` nests elements deeper than `maxDepth`, in one linear pass that
|
|
151
134
|
// follows what htmlparser2 builds: a start tag opens an element (a trailing "/" does not
|
|
152
135
|
// close it in HTML mode), an end tag closes down to the nearest open element of that name
|
|
@@ -188,7 +171,8 @@ function exceedsHtmlNestingDepth(html, maxDepth) {
|
|
|
188
171
|
if (stack.length > maxDepth) {
|
|
189
172
|
return true;
|
|
190
173
|
}
|
|
191
|
-
}
|
|
174
|
+
}
|
|
175
|
+
else if (open.get(name)) {
|
|
192
176
|
let popped;
|
|
193
177
|
do {
|
|
194
178
|
popped = stack.pop();
|
|
@@ -200,21 +184,17 @@ function exceedsHtmlNestingDepth(html, maxDepth) {
|
|
|
200
184
|
}
|
|
201
185
|
return false;
|
|
202
186
|
}
|
|
203
|
-
|
|
204
187
|
class IconvDecoder extends Transform {
|
|
205
188
|
constructor(Iconv, charset) {
|
|
206
189
|
super();
|
|
207
|
-
|
|
208
190
|
// Iconv throws error on ks_c_5601-1987 when it is mapped to EUC-KR
|
|
209
191
|
// https://github.com/bnoordhuis/node-iconv/issues/169
|
|
210
192
|
if (charset.toLowerCase() === 'ks_c_5601-1987') {
|
|
211
193
|
charset = 'CP949';
|
|
212
194
|
}
|
|
213
195
|
this.stream = new Iconv(charset, 'UTF-8//TRANSLIT//IGNORE');
|
|
214
|
-
|
|
215
196
|
this.inputEnded = false;
|
|
216
197
|
this.endCb = false;
|
|
217
|
-
|
|
218
198
|
this.stream.on('error', err => this.emit('error', err));
|
|
219
199
|
this.stream.on('data', chunk => this.push(chunk));
|
|
220
200
|
this.stream.on('end', () => {
|
|
@@ -224,37 +204,30 @@ class IconvDecoder extends Transform {
|
|
|
224
204
|
}
|
|
225
205
|
});
|
|
226
206
|
}
|
|
227
|
-
|
|
228
207
|
_transform(chunk, encoding, done) {
|
|
229
208
|
this.stream.write(chunk);
|
|
230
209
|
done();
|
|
231
210
|
}
|
|
232
|
-
|
|
233
211
|
_flush(done) {
|
|
234
212
|
this.endCb = done;
|
|
235
213
|
this.stream.end();
|
|
236
214
|
}
|
|
237
215
|
}
|
|
238
|
-
|
|
239
216
|
class JPDecoder extends Transform {
|
|
240
217
|
constructor(charset) {
|
|
241
218
|
super();
|
|
242
|
-
|
|
243
219
|
this.charset = charset;
|
|
244
220
|
this.chunks = [];
|
|
245
221
|
this.chunklen = 0;
|
|
246
222
|
}
|
|
247
|
-
|
|
248
223
|
_transform(chunk, encoding, done) {
|
|
249
224
|
if (typeof chunk === 'string') {
|
|
250
225
|
chunk = Buffer.from(chunk, encoding);
|
|
251
226
|
}
|
|
252
|
-
|
|
253
227
|
this.chunks.push(chunk);
|
|
254
228
|
this.chunklen += chunk.length;
|
|
255
229
|
done();
|
|
256
230
|
}
|
|
257
|
-
|
|
258
231
|
_flush(done) {
|
|
259
232
|
let input = Buffer.concat(this.chunks, this.chunklen);
|
|
260
233
|
try {
|
|
@@ -267,75 +240,73 @@ class JPDecoder extends Transform {
|
|
|
267
240
|
output = Buffer.from(output);
|
|
268
241
|
}
|
|
269
242
|
this.push(output);
|
|
270
|
-
}
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
271
245
|
// keep as is on errors
|
|
272
246
|
this.push(input);
|
|
273
247
|
}
|
|
274
|
-
|
|
275
248
|
done();
|
|
276
249
|
}
|
|
277
250
|
}
|
|
278
|
-
|
|
251
|
+
/**
|
|
252
|
+
* A lower level, streaming e-mail parser. It is a Transform stream: write the raw message in and
|
|
253
|
+
* read the parsed content out. It emits:
|
|
254
|
+
*
|
|
255
|
+
* - a `headers` event with the parsed headers of the message (see {@link Headers}),
|
|
256
|
+
* - a `headerLines` event with the raw header lines,
|
|
257
|
+
* - an {@link AttachmentStream} object for every attachment, whose content stream has to be read
|
|
258
|
+
* and `release()` called before the parser continues,
|
|
259
|
+
* - one {@link MessageText} object with the text content at the end.
|
|
260
|
+
*
|
|
261
|
+
* For one-shot parsing into a single object, use `simpleParser` instead.
|
|
262
|
+
*/
|
|
263
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging -- the interface below only narrows inherited stream methods
|
|
279
264
|
class MailParser extends Transform {
|
|
280
265
|
constructor(config) {
|
|
281
266
|
super({
|
|
282
267
|
readableObjectMode: true,
|
|
283
268
|
writableObjectMode: false
|
|
284
269
|
});
|
|
285
|
-
|
|
286
270
|
this.options = config || {};
|
|
271
|
+
// mailsplit declares its streams with only a 'data' event, the parser uses the other Transform events too
|
|
287
272
|
this.chunkedPassthrough = new ChunkedPassthrough();
|
|
288
273
|
this.splitter = new Splitter(config);
|
|
289
|
-
|
|
290
274
|
this.chunkedPassthrough.pipe(this.splitter);
|
|
291
|
-
|
|
292
275
|
this.finished = false;
|
|
293
276
|
this.waitingEnd = false;
|
|
294
|
-
|
|
295
277
|
this.headers = false;
|
|
296
278
|
this.headerLines = false;
|
|
297
|
-
|
|
298
279
|
this.endReceived = false;
|
|
299
280
|
this.reading = false;
|
|
300
281
|
this.hasFailed = false;
|
|
301
|
-
|
|
302
282
|
this.tree = false;
|
|
303
283
|
this.curnode = false;
|
|
304
284
|
this.waitUntilAttachmentEnd = false;
|
|
305
285
|
this.attachmentCallback = false;
|
|
306
|
-
|
|
307
286
|
this.hasHtml = false;
|
|
308
287
|
this.hasText = false;
|
|
309
|
-
|
|
310
288
|
this.text = false;
|
|
311
289
|
this.html = false;
|
|
312
290
|
this.textAsHtml = false;
|
|
313
291
|
this.linkifyWork = 0;
|
|
314
|
-
|
|
315
292
|
this.attachmentList = [];
|
|
316
|
-
|
|
317
293
|
this.textTypes = ['text/plain', 'text/html'].concat(!this.options.keepDeliveryStatus ? 'message/delivery-status' : []);
|
|
318
|
-
|
|
319
294
|
this.decoder = this.getDecoder();
|
|
320
|
-
|
|
321
295
|
this.chunkedPassthrough.on('error', err => {
|
|
322
296
|
this.splitter.emit('error', err);
|
|
323
297
|
});
|
|
324
|
-
|
|
325
298
|
this.splitter.on('readable', () => {
|
|
326
299
|
if (this.reading) {
|
|
327
300
|
return false;
|
|
328
301
|
}
|
|
329
302
|
this.readData();
|
|
330
303
|
});
|
|
331
|
-
|
|
332
304
|
this.splitter.on('end', () => {
|
|
333
305
|
this.endReceived = true;
|
|
334
306
|
if (!this.reading) {
|
|
335
307
|
this.endStream();
|
|
336
308
|
}
|
|
337
309
|
});
|
|
338
|
-
|
|
339
310
|
this.splitter.on('error', err => {
|
|
340
311
|
this.hasFailed = true;
|
|
341
312
|
if (typeof this.waitingEnd === 'function') {
|
|
@@ -343,10 +314,9 @@ class MailParser extends Transform {
|
|
|
343
314
|
}
|
|
344
315
|
this.emit('error', err);
|
|
345
316
|
});
|
|
346
|
-
|
|
347
317
|
this.libmime = new libmime.Libmime({ Iconv: this.options.Iconv });
|
|
348
318
|
}
|
|
349
|
-
|
|
319
|
+
/** @internal */
|
|
350
320
|
getDecoder() {
|
|
351
321
|
if (this.options.Iconv) {
|
|
352
322
|
const Iconv = this.options.Iconv;
|
|
@@ -358,7 +328,8 @@ class MailParser extends Transform {
|
|
|
358
328
|
return new IconvDecoder(Iconv, charset);
|
|
359
329
|
}
|
|
360
330
|
};
|
|
361
|
-
}
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
362
333
|
return {
|
|
363
334
|
decodeStream(charset) {
|
|
364
335
|
// resolve charset aliases (eg. iso-8859-8-i -> ISO-8859-8) via libmime's canonical table
|
|
@@ -367,13 +338,12 @@ class MailParser extends Transform {
|
|
|
367
338
|
// special case not supported by iconv-lite
|
|
368
339
|
return new JPDecoder(charset);
|
|
369
340
|
}
|
|
370
|
-
|
|
371
341
|
return iconv.decodeStream(charset);
|
|
372
342
|
}
|
|
373
343
|
};
|
|
374
344
|
}
|
|
375
345
|
}
|
|
376
|
-
|
|
346
|
+
/** @internal */
|
|
377
347
|
readData() {
|
|
378
348
|
if (this.hasFailed) {
|
|
379
349
|
return false;
|
|
@@ -387,7 +357,6 @@ class MailParser extends Transform {
|
|
|
387
357
|
}
|
|
388
358
|
return;
|
|
389
359
|
}
|
|
390
|
-
|
|
391
360
|
this.processChunk(data, err => {
|
|
392
361
|
if (err) {
|
|
393
362
|
if (typeof this.waitingEnd === 'function') {
|
|
@@ -398,10 +367,9 @@ class MailParser extends Transform {
|
|
|
398
367
|
setImmediate(() => this.readData());
|
|
399
368
|
});
|
|
400
369
|
}
|
|
401
|
-
|
|
370
|
+
/** @internal */
|
|
402
371
|
endStream() {
|
|
403
372
|
this.finished = true;
|
|
404
|
-
|
|
405
373
|
if (this.curnode && this.curnode.decoder) {
|
|
406
374
|
this.curnode.decoder.end();
|
|
407
375
|
}
|
|
@@ -409,21 +377,20 @@ class MailParser extends Transform {
|
|
|
409
377
|
this.waitingEnd();
|
|
410
378
|
}
|
|
411
379
|
}
|
|
412
|
-
|
|
413
380
|
_transform(chunk, encoding, done) {
|
|
414
381
|
if (!chunk || !chunk.length) {
|
|
415
382
|
return done();
|
|
416
383
|
}
|
|
417
|
-
|
|
418
384
|
if (this.chunkedPassthrough.write(chunk) === false) {
|
|
419
|
-
|
|
385
|
+
this.chunkedPassthrough.once('drain', () => {
|
|
420
386
|
done();
|
|
421
387
|
});
|
|
422
|
-
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
423
391
|
return done();
|
|
424
392
|
}
|
|
425
393
|
}
|
|
426
|
-
|
|
427
394
|
_flush(done) {
|
|
428
395
|
setImmediate(() => this.chunkedPassthrough.end());
|
|
429
396
|
if (this.finished) {
|
|
@@ -438,32 +405,32 @@ class MailParser extends Transform {
|
|
|
438
405
|
this.cleanup(done);
|
|
439
406
|
};
|
|
440
407
|
}
|
|
441
|
-
|
|
408
|
+
/** @internal */
|
|
442
409
|
cleanup(done) {
|
|
443
410
|
let finish = () => {
|
|
444
411
|
try {
|
|
445
412
|
let t = this.getTextContent();
|
|
446
413
|
this.push(t);
|
|
447
|
-
}
|
|
414
|
+
}
|
|
415
|
+
catch (err) {
|
|
448
416
|
// report through the stream instead of leaving _flush hanging
|
|
449
417
|
return done(err);
|
|
450
418
|
}
|
|
451
|
-
|
|
452
419
|
done();
|
|
453
420
|
};
|
|
454
|
-
|
|
455
421
|
if (this.curnode && this.curnode.decoder && this.curnode.decoder.readable && !this.decoderEnded) {
|
|
456
422
|
(this.curnode.contentStream || this.curnode.decoder).once('end', () => {
|
|
457
423
|
finish();
|
|
458
424
|
});
|
|
459
425
|
this.curnode.decoder.end();
|
|
460
|
-
}
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
461
428
|
setImmediate(() => {
|
|
462
429
|
finish();
|
|
463
430
|
});
|
|
464
431
|
}
|
|
465
432
|
}
|
|
466
|
-
|
|
433
|
+
/** @internal */
|
|
467
434
|
processHeaders(lines) {
|
|
468
435
|
let headers = new Map();
|
|
469
436
|
(lines || []).forEach(line => {
|
|
@@ -486,7 +453,8 @@ class MailParser extends Transform {
|
|
|
486
453
|
}
|
|
487
454
|
try {
|
|
488
455
|
value.params[key] = this.libmime.decodeWords(value.params[key]);
|
|
489
|
-
}
|
|
456
|
+
}
|
|
457
|
+
catch {
|
|
490
458
|
// ignore, keep as is
|
|
491
459
|
}
|
|
492
460
|
});
|
|
@@ -494,7 +462,7 @@ class MailParser extends Transform {
|
|
|
494
462
|
}
|
|
495
463
|
case 'date': {
|
|
496
464
|
let dateValue = new Date(value);
|
|
497
|
-
if (isNaN(dateValue)) {
|
|
465
|
+
if (isNaN(dateValue.getTime())) {
|
|
498
466
|
// date parsing failed :S
|
|
499
467
|
dateValue = new Date();
|
|
500
468
|
}
|
|
@@ -504,26 +472,29 @@ class MailParser extends Transform {
|
|
|
504
472
|
case 'subject':
|
|
505
473
|
try {
|
|
506
474
|
value = this.libmime.decodeWords(value);
|
|
507
|
-
}
|
|
475
|
+
}
|
|
476
|
+
catch {
|
|
508
477
|
// ignore, keep as is
|
|
509
478
|
}
|
|
510
479
|
break;
|
|
511
480
|
case 'references':
|
|
512
481
|
try {
|
|
513
482
|
value = this.libmime.decodeWords(value);
|
|
514
|
-
}
|
|
483
|
+
}
|
|
484
|
+
catch {
|
|
515
485
|
// ignore
|
|
516
486
|
}
|
|
517
487
|
value = value
|
|
518
488
|
.split(/\s+/)
|
|
519
489
|
.map(this.ensureMessageIDFormat)
|
|
520
|
-
.filter(val => val);
|
|
490
|
+
.filter((val) => val);
|
|
521
491
|
break;
|
|
522
492
|
case 'message-id':
|
|
523
493
|
case 'in-reply-to':
|
|
524
494
|
try {
|
|
525
495
|
value = this.libmime.decodeWords(value);
|
|
526
|
-
}
|
|
496
|
+
}
|
|
497
|
+
catch {
|
|
527
498
|
// ignore
|
|
528
499
|
}
|
|
529
500
|
value = this.ensureMessageIDFormat(value);
|
|
@@ -553,29 +524,28 @@ class MailParser extends Transform {
|
|
|
553
524
|
};
|
|
554
525
|
break;
|
|
555
526
|
}
|
|
556
|
-
|
|
557
527
|
// handle list-* keys
|
|
558
|
-
if (key.
|
|
559
|
-
value = this.parseListHeader(key.
|
|
528
|
+
if (key.slice(0, 5) === 'list-') {
|
|
529
|
+
value = this.parseListHeader(key.slice(5), value);
|
|
560
530
|
key = 'list';
|
|
561
531
|
}
|
|
562
|
-
|
|
563
532
|
if (value) {
|
|
564
533
|
if (!headers.has(key)) {
|
|
565
534
|
headers.set(key, [].concat(value || []));
|
|
566
|
-
}
|
|
535
|
+
}
|
|
536
|
+
else if (Array.isArray(value)) {
|
|
567
537
|
// appended in place: rebuilding the list with concat for every repeated
|
|
568
538
|
// header was quadratic in the number of References lines
|
|
569
539
|
let list = headers.get(key);
|
|
570
540
|
for (let entry of value) {
|
|
571
541
|
list.push(entry);
|
|
572
542
|
}
|
|
573
|
-
}
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
574
545
|
headers.get(key).push(value);
|
|
575
546
|
}
|
|
576
547
|
}
|
|
577
548
|
});
|
|
578
|
-
|
|
579
549
|
// keep only the first value
|
|
580
550
|
let singleKeys = [
|
|
581
551
|
'message-id',
|
|
@@ -596,22 +566,21 @@ class MailParser extends Transform {
|
|
|
596
566
|
'errors-to',
|
|
597
567
|
'disposition-notification-to'
|
|
598
568
|
];
|
|
599
|
-
|
|
600
569
|
headers.forEach((value, key) => {
|
|
601
570
|
if (Array.isArray(value)) {
|
|
602
571
|
if (singleKeys.includes(key) && value.length) {
|
|
603
572
|
// the first occurrence: the one mailsplit built the MIME structure from,
|
|
604
573
|
// and the one mail clients display when the header is duplicated
|
|
605
574
|
headers.set(key, value[0]);
|
|
606
|
-
}
|
|
575
|
+
}
|
|
576
|
+
else if (value.length === 1) {
|
|
607
577
|
headers.set(key, value[0]);
|
|
608
578
|
}
|
|
609
579
|
}
|
|
610
|
-
|
|
611
580
|
if (key === 'list') {
|
|
612
581
|
// normalize List-* headers
|
|
613
582
|
let listValue = {};
|
|
614
|
-
[].concat(value || []).forEach(val => {
|
|
583
|
+
[].concat(value || []).forEach((val) => {
|
|
615
584
|
Object.keys(val || {}).forEach(listKey => {
|
|
616
585
|
listValue[listKey] = val[listKey];
|
|
617
586
|
});
|
|
@@ -619,10 +588,9 @@ class MailParser extends Transform {
|
|
|
619
588
|
headers.set(key, listValue);
|
|
620
589
|
}
|
|
621
590
|
});
|
|
622
|
-
|
|
623
591
|
return headers;
|
|
624
592
|
}
|
|
625
|
-
|
|
593
|
+
/** @internal */
|
|
626
594
|
parseListHeader(key, value) {
|
|
627
595
|
if (UNSAFE_LIST_KEYS.has(key)) {
|
|
628
596
|
// would replace the prototype of (or shadow) the normalized list object
|
|
@@ -632,23 +600,26 @@ class MailParser extends Transform {
|
|
|
632
600
|
let response = {};
|
|
633
601
|
let data = addresses
|
|
634
602
|
.map(address => {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
603
|
+
if (/^https?:/i.test(address.name)) {
|
|
604
|
+
response.url = address.name;
|
|
605
|
+
}
|
|
606
|
+
else if (address.name) {
|
|
607
|
+
response.name = address.name;
|
|
608
|
+
}
|
|
609
|
+
if (/^mailto:/.test(address.address || '')) {
|
|
610
|
+
response.mail = address.address.slice(7);
|
|
611
|
+
}
|
|
612
|
+
else if (address.address && address.address.indexOf('@') < 0) {
|
|
613
|
+
response.id = address.address;
|
|
614
|
+
}
|
|
615
|
+
else if (address.address) {
|
|
616
|
+
response.mail = address.address;
|
|
617
|
+
}
|
|
618
|
+
if (Object.keys(response).length) {
|
|
619
|
+
return response;
|
|
620
|
+
}
|
|
621
|
+
return false;
|
|
622
|
+
})
|
|
652
623
|
.filter(address => address);
|
|
653
624
|
if (data.length) {
|
|
654
625
|
return {
|
|
@@ -657,20 +628,26 @@ class MailParser extends Transform {
|
|
|
657
628
|
}
|
|
658
629
|
return false;
|
|
659
630
|
}
|
|
660
|
-
|
|
631
|
+
/**
|
|
632
|
+
* Turns a `Priority`, `X-Priority`, `X-MSMail-Priority` or `Importance` header value into
|
|
633
|
+
* `'high'`, `'normal'` or `'low'`.
|
|
634
|
+
*/
|
|
661
635
|
parsePriority(value) {
|
|
662
636
|
value = value.toLowerCase().trim();
|
|
663
637
|
if (!isNaN(parseInt(value, 10))) {
|
|
664
638
|
// support "X-Priority: 1 (Highest)"
|
|
665
|
-
|
|
666
|
-
if (
|
|
639
|
+
let level = parseInt(value, 10) || 0;
|
|
640
|
+
if (level === 3) {
|
|
667
641
|
return 'normal';
|
|
668
|
-
}
|
|
642
|
+
}
|
|
643
|
+
else if (level > 3) {
|
|
669
644
|
return 'low';
|
|
670
|
-
}
|
|
645
|
+
}
|
|
646
|
+
else {
|
|
671
647
|
return 'high';
|
|
672
648
|
}
|
|
673
|
-
}
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
674
651
|
switch (value) {
|
|
675
652
|
case 'non-urgent':
|
|
676
653
|
case 'low':
|
|
@@ -682,28 +659,26 @@ class MailParser extends Transform {
|
|
|
682
659
|
}
|
|
683
660
|
return 'normal';
|
|
684
661
|
}
|
|
685
|
-
|
|
662
|
+
/**
|
|
663
|
+
* Wraps a Message-ID in angle brackets where they are missing. Returns `false` for an empty value.
|
|
664
|
+
*/
|
|
686
665
|
ensureMessageIDFormat(value) {
|
|
687
666
|
if (!value.length) {
|
|
688
667
|
return false;
|
|
689
668
|
}
|
|
690
|
-
|
|
691
669
|
if (value.charAt(0) !== '<') {
|
|
692
670
|
value = '<' + value;
|
|
693
671
|
}
|
|
694
|
-
|
|
695
672
|
if (value.charAt(value.length - 1) !== '>') {
|
|
696
673
|
value += '>';
|
|
697
674
|
}
|
|
698
|
-
|
|
699
675
|
return value;
|
|
700
676
|
}
|
|
701
|
-
|
|
677
|
+
/** @internal */
|
|
702
678
|
decodeAddresses(addresses) {
|
|
703
679
|
for (let i = 0; i < addresses.length; i++) {
|
|
704
680
|
let address = addresses[i];
|
|
705
681
|
address.name = (address.name || '').toString().trim();
|
|
706
|
-
|
|
707
682
|
// An encoded word decodes into the display name and nothing else, whatever it
|
|
708
683
|
// decodes to. RFC 2047 section 5 keeps encoded words out of the addr-spec, so a
|
|
709
684
|
// name that decodes to "CEO" <ceo@bank.com> is still only a name: parsing it
|
|
@@ -711,7 +686,8 @@ class MailParser extends Transform {
|
|
|
711
686
|
if (address.name) {
|
|
712
687
|
try {
|
|
713
688
|
address.name = this.libmime.decodeWords(address.name);
|
|
714
|
-
}
|
|
689
|
+
}
|
|
690
|
+
catch {
|
|
715
691
|
//ignore, keep as is
|
|
716
692
|
}
|
|
717
693
|
}
|
|
@@ -723,19 +699,22 @@ class MailParser extends Transform {
|
|
|
723
699
|
let decodedAddr = this.libmime.decodeWords(address.address);
|
|
724
700
|
if (/^[^\s@]+@[^\s@]+$/.test(decodedAddr) && !/[=]\?/.test(decodedAddr)) {
|
|
725
701
|
address.address = decodedAddr;
|
|
726
|
-
}
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
727
704
|
address.address = '';
|
|
728
705
|
}
|
|
729
|
-
}
|
|
706
|
+
}
|
|
707
|
+
catch {
|
|
730
708
|
address.address = '';
|
|
731
709
|
}
|
|
732
710
|
}
|
|
733
|
-
if (/@xn--/.test(address.address)) {
|
|
711
|
+
if (address.address && /@xn--/.test(address.address)) {
|
|
734
712
|
try {
|
|
735
713
|
address.address =
|
|
736
|
-
address.address.
|
|
737
|
-
|
|
738
|
-
}
|
|
714
|
+
address.address.slice(0, address.address.lastIndexOf('@') + 1) +
|
|
715
|
+
punycode.toUnicode(address.address.slice(address.address.lastIndexOf('@') + 1));
|
|
716
|
+
}
|
|
717
|
+
catch {
|
|
739
718
|
// Not a valid punycode string; keep as is
|
|
740
719
|
}
|
|
741
720
|
}
|
|
@@ -744,17 +723,15 @@ class MailParser extends Transform {
|
|
|
744
723
|
}
|
|
745
724
|
}
|
|
746
725
|
}
|
|
747
|
-
|
|
726
|
+
/** @internal */
|
|
748
727
|
createNode(node) {
|
|
749
728
|
let contentType = node.contentType;
|
|
750
729
|
let disposition = node.disposition;
|
|
751
730
|
let encoding = node.encoding;
|
|
752
731
|
let charset = node.charset;
|
|
753
|
-
|
|
754
732
|
if (!contentType && node.root) {
|
|
755
733
|
contentType = 'text/plain';
|
|
756
734
|
}
|
|
757
|
-
|
|
758
735
|
let newNode = {
|
|
759
736
|
node,
|
|
760
737
|
headerLines: node.headers.lines,
|
|
@@ -762,46 +739,37 @@ class MailParser extends Transform {
|
|
|
762
739
|
contentType,
|
|
763
740
|
children: []
|
|
764
741
|
};
|
|
765
|
-
|
|
766
742
|
if (!/^multipart\//i.test(contentType)) {
|
|
767
743
|
if (disposition && !['attachment', 'inline'].includes(disposition)) {
|
|
768
744
|
disposition = 'attachment';
|
|
769
745
|
}
|
|
770
|
-
|
|
771
746
|
if (!disposition && !this.textTypes.includes(contentType)) {
|
|
772
747
|
newNode.disposition = 'attachment';
|
|
773
|
-
}
|
|
748
|
+
}
|
|
749
|
+
else {
|
|
774
750
|
newNode.disposition = disposition || 'inline';
|
|
775
751
|
}
|
|
776
|
-
|
|
777
752
|
newNode.isAttachment = !this.textTypes.includes(contentType) || newNode.disposition !== 'inline';
|
|
778
|
-
|
|
779
753
|
newNode.encoding = ['quoted-printable', 'base64'].includes(encoding) ? encoding : 'binary';
|
|
780
|
-
|
|
781
754
|
if (charset) {
|
|
782
755
|
newNode.charset = charset;
|
|
783
756
|
}
|
|
784
|
-
|
|
785
757
|
let decoder = node.getDecoder();
|
|
786
758
|
decoder.on('end', () => {
|
|
787
759
|
this.decoderEnded = true;
|
|
788
760
|
});
|
|
789
761
|
newNode.decoder = decoder;
|
|
790
762
|
}
|
|
791
|
-
|
|
792
763
|
if (node.root) {
|
|
793
764
|
this.headers = newNode.headers;
|
|
794
765
|
this.headerLines = newNode.headerLines;
|
|
795
766
|
}
|
|
796
|
-
|
|
797
767
|
// find location in tree
|
|
798
|
-
|
|
799
|
-
if (!this.tree) {
|
|
768
|
+
if (!this.tree || !this.curnode) {
|
|
800
769
|
newNode.root = true;
|
|
801
770
|
this.curnode = this.tree = newNode;
|
|
802
771
|
return newNode;
|
|
803
772
|
}
|
|
804
|
-
|
|
805
773
|
// immediate child of root node
|
|
806
774
|
if (!this.curnode.parent) {
|
|
807
775
|
newNode.parent = this.curnode;
|
|
@@ -809,7 +777,6 @@ class MailParser extends Transform {
|
|
|
809
777
|
this.curnode = newNode;
|
|
810
778
|
return newNode;
|
|
811
779
|
}
|
|
812
|
-
|
|
813
780
|
// siblings
|
|
814
781
|
if (this.curnode.parent.node === node.parentNode) {
|
|
815
782
|
newNode.parent = this.curnode.parent;
|
|
@@ -817,7 +784,6 @@ class MailParser extends Transform {
|
|
|
817
784
|
this.curnode = newNode;
|
|
818
785
|
return newNode;
|
|
819
786
|
}
|
|
820
|
-
|
|
821
787
|
// first child
|
|
822
788
|
if (this.curnode.node === node.parentNode) {
|
|
823
789
|
newNode.parent = this.curnode;
|
|
@@ -825,7 +791,6 @@ class MailParser extends Transform {
|
|
|
825
791
|
this.curnode = newNode;
|
|
826
792
|
return newNode;
|
|
827
793
|
}
|
|
828
|
-
|
|
829
794
|
// move up
|
|
830
795
|
let parentNode = this.curnode;
|
|
831
796
|
while ((parentNode = parentNode.parent)) {
|
|
@@ -836,12 +801,11 @@ class MailParser extends Transform {
|
|
|
836
801
|
return newNode;
|
|
837
802
|
}
|
|
838
803
|
}
|
|
839
|
-
|
|
840
804
|
// should never happen, can't detect parent
|
|
841
805
|
this.curnode = newNode;
|
|
842
806
|
return newNode;
|
|
843
807
|
}
|
|
844
|
-
|
|
808
|
+
/** @internal */
|
|
845
809
|
getTextContent() {
|
|
846
810
|
let text = [];
|
|
847
811
|
let html = [];
|
|
@@ -850,71 +814,66 @@ class MailParser extends Transform {
|
|
|
850
814
|
if (node.showMeta) {
|
|
851
815
|
let meta = ['From', 'Subject', 'Date', 'To', 'Cc', 'Bcc']
|
|
852
816
|
.map(fkey => {
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
817
|
+
let key = fkey.toLowerCase();
|
|
818
|
+
if (!node.headers.has(key)) {
|
|
819
|
+
return false;
|
|
820
|
+
}
|
|
821
|
+
let value = node.headers.get(key);
|
|
822
|
+
if (!value) {
|
|
823
|
+
return false;
|
|
824
|
+
}
|
|
825
|
+
return {
|
|
826
|
+
key: fkey,
|
|
827
|
+
value: (Array.isArray(value) ? value[value.length - 1] : value)
|
|
828
|
+
};
|
|
829
|
+
})
|
|
866
830
|
.filter(entry => entry);
|
|
867
831
|
if (this.hasHtml) {
|
|
868
|
-
html.push(
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
.join('\n') +
|
|
893
|
-
'<table>'
|
|
894
|
-
);
|
|
832
|
+
html.push('<table class="mp_head">' +
|
|
833
|
+
meta
|
|
834
|
+
.map(entry => {
|
|
835
|
+
let value = entry.value;
|
|
836
|
+
switch (entry.key) {
|
|
837
|
+
case 'From':
|
|
838
|
+
case 'To':
|
|
839
|
+
case 'Cc':
|
|
840
|
+
case 'Bcc':
|
|
841
|
+
value = value.html;
|
|
842
|
+
break;
|
|
843
|
+
case 'Date':
|
|
844
|
+
value = this.options.formatDateString ? this.options.formatDateString(value) : value.toUTCString();
|
|
845
|
+
break;
|
|
846
|
+
case 'Subject':
|
|
847
|
+
value = '<strong>' + he.encode(value) + '</strong>';
|
|
848
|
+
break;
|
|
849
|
+
default:
|
|
850
|
+
value = he.encode(value);
|
|
851
|
+
}
|
|
852
|
+
return '<tr><td class="mp_head_key">' + he.encode(entry.key) + ':</td><td class="mp_head_value">' + value + '<td></tr>';
|
|
853
|
+
})
|
|
854
|
+
.join('\n') +
|
|
855
|
+
'<table>');
|
|
895
856
|
}
|
|
896
857
|
if (this.hasText) {
|
|
897
|
-
text.push(
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
'\n'
|
|
917
|
-
);
|
|
858
|
+
text.push('\n' +
|
|
859
|
+
meta
|
|
860
|
+
.map(entry => {
|
|
861
|
+
let value = entry.value;
|
|
862
|
+
switch (entry.key) {
|
|
863
|
+
case 'From':
|
|
864
|
+
case 'To':
|
|
865
|
+
case 'Cc':
|
|
866
|
+
case 'Bcc':
|
|
867
|
+
value = value.text;
|
|
868
|
+
break;
|
|
869
|
+
case 'Date':
|
|
870
|
+
value = this.options.formatDateString ? this.options.formatDateString(value) : value.toUTCString();
|
|
871
|
+
break;
|
|
872
|
+
}
|
|
873
|
+
return entry.key + ': ' + value;
|
|
874
|
+
})
|
|
875
|
+
.join('\n') +
|
|
876
|
+
'\n');
|
|
918
877
|
}
|
|
919
878
|
}
|
|
920
879
|
if (node.textContent) {
|
|
@@ -923,16 +882,19 @@ class MailParser extends Transform {
|
|
|
923
882
|
if (!alternative && this.hasHtml) {
|
|
924
883
|
html.push(this.textToHtml(node.textContent));
|
|
925
884
|
}
|
|
926
|
-
}
|
|
885
|
+
}
|
|
886
|
+
else if (node.contentType === 'message/delivery-status' && !this.options.keepDeliveryStatus) {
|
|
927
887
|
text.push(node.textContent);
|
|
928
888
|
if (!alternative && this.hasHtml) {
|
|
929
889
|
html.push(this.textToHtml(node.textContent));
|
|
930
890
|
}
|
|
931
|
-
}
|
|
891
|
+
}
|
|
892
|
+
else if (node.contentType === 'text/html') {
|
|
932
893
|
if ((!alternative && this.hasText) || (node.root && !this.hasText)) {
|
|
933
894
|
if (this.options.skipHtmlToText) {
|
|
934
895
|
text.push('');
|
|
935
|
-
}
|
|
896
|
+
}
|
|
897
|
+
else {
|
|
936
898
|
// HTML that can not be converted is no reason to lose the message:
|
|
937
899
|
// the text stays empty, the HTML is kept and the reason travels with
|
|
938
900
|
// the result as textConversionError. An 'error' event here used to
|
|
@@ -941,12 +903,15 @@ class MailParser extends Transform {
|
|
|
941
903
|
let err = null;
|
|
942
904
|
if (node.textContent.length > this.options.maxHtmlLengthToParse) {
|
|
943
905
|
err = new Error(`HTML too long for parsing ${node.textContent.length} bytes`);
|
|
944
|
-
}
|
|
906
|
+
}
|
|
907
|
+
else if (exceedsHtmlNestingDepth(node.textContent, MAX_HTML_NESTING_DEPTH)) {
|
|
945
908
|
err = new Error(`HTML nested deeper than ${MAX_HTML_NESTING_DEPTH} levels`);
|
|
946
|
-
}
|
|
909
|
+
}
|
|
910
|
+
else {
|
|
947
911
|
try {
|
|
948
912
|
text.push(htmlToText(node.textContent, { limits: { maxDepth: MAX_HTML_NESTING_DEPTH } }));
|
|
949
|
-
}
|
|
913
|
+
}
|
|
914
|
+
catch (cause) {
|
|
950
915
|
err = new Error('Failed to parse HTML', { cause });
|
|
951
916
|
}
|
|
952
917
|
}
|
|
@@ -966,9 +931,7 @@ class MailParser extends Transform {
|
|
|
966
931
|
});
|
|
967
932
|
}
|
|
968
933
|
};
|
|
969
|
-
|
|
970
934
|
processNode(false, 0, this.tree);
|
|
971
|
-
|
|
972
935
|
let response = {
|
|
973
936
|
type: 'text'
|
|
974
937
|
};
|
|
@@ -984,7 +947,7 @@ class MailParser extends Transform {
|
|
|
984
947
|
}
|
|
985
948
|
return response;
|
|
986
949
|
}
|
|
987
|
-
|
|
950
|
+
/** @internal */
|
|
988
951
|
processChunk(data, done) {
|
|
989
952
|
let partId = null;
|
|
990
953
|
if (data._parentBoundary) {
|
|
@@ -1001,31 +964,26 @@ class MailParser extends Transform {
|
|
|
1001
964
|
}
|
|
1002
965
|
});
|
|
1003
966
|
this.emit('headers', node.headers);
|
|
1004
|
-
|
|
1005
967
|
if (node.headerLines) {
|
|
1006
968
|
this.emit('headerLines', node.headerLines);
|
|
1007
969
|
}
|
|
1008
970
|
}
|
|
1009
|
-
|
|
1010
971
|
if (data.contentType === 'message/rfc822' && data.messageNode) {
|
|
1011
972
|
break;
|
|
1012
973
|
}
|
|
1013
|
-
|
|
1014
974
|
if (data.parentNode && data.parentNode.contentType === 'message/rfc822') {
|
|
1015
975
|
node.showMeta = true;
|
|
1016
976
|
}
|
|
1017
|
-
|
|
1018
977
|
if (node.isAttachment) {
|
|
978
|
+
let decoder = node.decoder;
|
|
1019
979
|
let contentType = node.contentType;
|
|
1020
980
|
if (node.contentType === 'application/octet-stream' && data.filename) {
|
|
1021
981
|
contentType = this.libmime.detectMimeType(data.filename) || 'application/octet-stream';
|
|
1022
982
|
}
|
|
1023
|
-
|
|
1024
983
|
// backpressure state for the attachment stream, see pump() below
|
|
1025
984
|
let released = false;
|
|
1026
985
|
let waitingDrain = false;
|
|
1027
|
-
let pump
|
|
1028
|
-
|
|
986
|
+
let pump;
|
|
1029
987
|
let attachment = {
|
|
1030
988
|
type: 'attachment',
|
|
1031
989
|
content: null,
|
|
@@ -1045,59 +1003,53 @@ class MailParser extends Transform {
|
|
|
1045
1003
|
this.waitUntilAttachmentEnd = false;
|
|
1046
1004
|
}
|
|
1047
1005
|
};
|
|
1048
|
-
|
|
1049
1006
|
let algo = this.options.checksumAlgo || 'md5';
|
|
1050
1007
|
let hasher;
|
|
1051
1008
|
try {
|
|
1052
1009
|
hasher = new StreamHash(attachment, algo);
|
|
1053
|
-
}
|
|
1010
|
+
}
|
|
1011
|
+
catch (err) {
|
|
1054
1012
|
// an algorithm this Node does not offer (a typo, or MD5 on a host whose
|
|
1055
1013
|
// OpenSSL runs in FIPS mode) is a parser error, not a process-ending throw
|
|
1056
1014
|
err.message = `Checksum algorithm "${algo}" is not available: ${err.message}`;
|
|
1057
1015
|
return done(err);
|
|
1058
1016
|
}
|
|
1059
|
-
|
|
1017
|
+
decoder.on('error', err => {
|
|
1060
1018
|
hasher.emit('error', err);
|
|
1061
1019
|
});
|
|
1062
|
-
|
|
1063
1020
|
// Honour the consumer's backpressure while it reads the attachment. Once the
|
|
1064
1021
|
// attachment is released it is drained regardless, so that a caller that
|
|
1065
1022
|
// releases without reading the content does not stall the parser.
|
|
1066
1023
|
pump = () => {
|
|
1067
1024
|
let chunk;
|
|
1068
|
-
while ((chunk =
|
|
1025
|
+
while ((chunk = decoder.read()) !== null) {
|
|
1069
1026
|
if (hasher.write(chunk) === false && !released) {
|
|
1070
1027
|
waitingDrain = true;
|
|
1071
|
-
|
|
1028
|
+
hasher.once('drain', () => {
|
|
1072
1029
|
waitingDrain = false;
|
|
1073
1030
|
pump();
|
|
1074
1031
|
});
|
|
1032
|
+
return;
|
|
1075
1033
|
}
|
|
1076
1034
|
}
|
|
1077
1035
|
};
|
|
1078
|
-
|
|
1079
|
-
node.decoder.on('readable', () => {
|
|
1036
|
+
decoder.on('readable', () => {
|
|
1080
1037
|
if (!waitingDrain) {
|
|
1081
1038
|
pump();
|
|
1082
1039
|
}
|
|
1083
1040
|
});
|
|
1084
|
-
|
|
1085
|
-
node.decoder.once('end', () => {
|
|
1041
|
+
decoder.once('end', () => {
|
|
1086
1042
|
hasher.end();
|
|
1087
1043
|
});
|
|
1088
|
-
|
|
1089
1044
|
//node.decoder.pipe(hasher);
|
|
1090
1045
|
attachment.content = hasher;
|
|
1091
|
-
|
|
1092
1046
|
this.waitUntilAttachmentEnd = true;
|
|
1093
1047
|
if (data.disposition) {
|
|
1094
1048
|
attachment.contentDisposition = data.disposition;
|
|
1095
1049
|
}
|
|
1096
|
-
|
|
1097
1050
|
if (data.filename) {
|
|
1098
1051
|
attachment.filename = data.filename;
|
|
1099
1052
|
}
|
|
1100
|
-
|
|
1101
1053
|
if (node.headers.has('content-id')) {
|
|
1102
1054
|
attachment.contentId = [].concat(node.headers.get('content-id') || []).shift();
|
|
1103
1055
|
attachment.cid = attachment.contentId.trim().replace(/^<|>$/g, '').trim();
|
|
@@ -1109,23 +1061,23 @@ class MailParser extends Transform {
|
|
|
1109
1061
|
}
|
|
1110
1062
|
}
|
|
1111
1063
|
}
|
|
1112
|
-
|
|
1113
1064
|
attachment.headers = node.headers;
|
|
1114
1065
|
this.push(attachment);
|
|
1115
1066
|
this.attachmentList.push(attachment);
|
|
1116
|
-
}
|
|
1067
|
+
}
|
|
1068
|
+
else if (node.disposition === 'inline') {
|
|
1117
1069
|
let chunks = [];
|
|
1118
1070
|
let chunklen = 0;
|
|
1119
1071
|
node.contentStream = node.decoder;
|
|
1120
|
-
|
|
1121
1072
|
if (node.contentType === 'text/plain') {
|
|
1122
1073
|
this.hasText = true;
|
|
1123
|
-
}
|
|
1074
|
+
}
|
|
1075
|
+
else if (node.contentType === 'text/html') {
|
|
1124
1076
|
this.hasHtml = true;
|
|
1125
|
-
}
|
|
1077
|
+
}
|
|
1078
|
+
else if (node.contentType === 'message/delivery-status' && !this.options.keepDeliveryStatus) {
|
|
1126
1079
|
this.hasText = true;
|
|
1127
1080
|
}
|
|
1128
|
-
|
|
1129
1081
|
if (node.node.flowed) {
|
|
1130
1082
|
let contentStream = node.contentStream;
|
|
1131
1083
|
let flowDecoder = new FlowedDecoder({
|
|
@@ -1137,10 +1089,8 @@ class MailParser extends Transform {
|
|
|
1137
1089
|
contentStream.pipe(flowDecoder);
|
|
1138
1090
|
node.contentStream = flowDecoder;
|
|
1139
1091
|
}
|
|
1140
|
-
|
|
1141
1092
|
let charset = node.charset || 'utf-8';
|
|
1142
1093
|
//charset = charset || 'windows-1257';
|
|
1143
|
-
|
|
1144
1094
|
if (!['ascii', 'usascii', 'utf8'].includes(charset.toLowerCase().replace(/[^a-z0-9]+/g, ''))) {
|
|
1145
1095
|
try {
|
|
1146
1096
|
let contentStream = node.contentStream;
|
|
@@ -1150,14 +1100,15 @@ class MailParser extends Transform {
|
|
|
1150
1100
|
});
|
|
1151
1101
|
contentStream.pipe(decodeStream);
|
|
1152
1102
|
node.contentStream = decodeStream;
|
|
1153
|
-
}
|
|
1103
|
+
}
|
|
1104
|
+
catch {
|
|
1154
1105
|
// do not decode charset
|
|
1155
1106
|
}
|
|
1156
1107
|
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1108
|
+
let contentStream = node.contentStream;
|
|
1109
|
+
contentStream.on('readable', () => {
|
|
1159
1110
|
let chunk;
|
|
1160
|
-
while ((chunk =
|
|
1111
|
+
while ((chunk = contentStream.read()) !== null) {
|
|
1161
1112
|
if (typeof chunk === 'string') {
|
|
1162
1113
|
chunk = Buffer.from(chunk);
|
|
1163
1114
|
}
|
|
@@ -1165,114 +1116,113 @@ class MailParser extends Transform {
|
|
|
1165
1116
|
chunklen += chunk.length;
|
|
1166
1117
|
}
|
|
1167
1118
|
});
|
|
1168
|
-
|
|
1169
|
-
node.contentStream.once('end', () => {
|
|
1119
|
+
contentStream.once('end', () => {
|
|
1170
1120
|
node.textContent = Buffer.concat(chunks, chunklen).toString().replace(/\r?\n/g, '\n');
|
|
1171
1121
|
});
|
|
1172
|
-
|
|
1173
|
-
node.contentStream.once('error', err => {
|
|
1122
|
+
contentStream.once('error', err => {
|
|
1174
1123
|
this.emit('error', err);
|
|
1175
1124
|
});
|
|
1176
1125
|
}
|
|
1177
|
-
|
|
1178
1126
|
break;
|
|
1179
1127
|
}
|
|
1180
|
-
|
|
1181
1128
|
case 'data':
|
|
1182
1129
|
if (this.curnode && this.curnode.decoder) {
|
|
1183
1130
|
this.curnode.decoder.end();
|
|
1184
1131
|
}
|
|
1185
|
-
|
|
1186
1132
|
if (this.waitUntilAttachmentEnd) {
|
|
1187
1133
|
this.attachmentCallback = done;
|
|
1188
1134
|
return;
|
|
1189
1135
|
}
|
|
1190
|
-
|
|
1191
1136
|
// multipart message structure
|
|
1192
1137
|
// this is not related to any specific 'node' block as it includes
|
|
1193
1138
|
// everything between the end of some node body and between the next header
|
|
1194
1139
|
//process.stdout.write(data.value);
|
|
1195
1140
|
break;
|
|
1196
|
-
|
|
1197
1141
|
case 'body':
|
|
1198
1142
|
if (this.curnode && this.curnode.decoder && this.curnode.decoder.writable) {
|
|
1199
1143
|
if (this.curnode.decoder.write(data.value) === false) {
|
|
1200
|
-
|
|
1144
|
+
this.curnode.decoder.once('drain', done);
|
|
1145
|
+
return;
|
|
1201
1146
|
}
|
|
1202
1147
|
}
|
|
1203
|
-
|
|
1204
1148
|
// Leaf element body. Includes the body for the last 'node' block. You might
|
|
1205
1149
|
// have several 'body' calls for a single 'node' block
|
|
1206
1150
|
//process.stdout.write(data.value);
|
|
1207
1151
|
break;
|
|
1208
1152
|
}
|
|
1209
|
-
|
|
1210
1153
|
setImmediate(done);
|
|
1211
1154
|
}
|
|
1212
|
-
|
|
1155
|
+
/**
|
|
1156
|
+
* Formats parsed addresses for an HTML context, every value HTML-escaped.
|
|
1157
|
+
*/
|
|
1213
1158
|
getAddressesHTML(value) {
|
|
1214
|
-
let formatSingleLevel = addresses =>
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1159
|
+
let formatSingleLevel = (addresses) => addresses
|
|
1160
|
+
.map(address => {
|
|
1161
|
+
let str = '<span class="mp_address_group">';
|
|
1162
|
+
if (address.name) {
|
|
1163
|
+
str += '<span class="mp_address_name">' + he.encode(address.name) + (address.group ? ': ' : '') + '</span>';
|
|
1164
|
+
}
|
|
1165
|
+
if (address.address) {
|
|
1166
|
+
let link = '<a href="mailto:' + he.encode(address.address) + '" class="mp_address_email">' + he.encode(address.address) + '</a>';
|
|
1167
|
+
if (address.name) {
|
|
1168
|
+
str += ' <' + link + '>';
|
|
1169
|
+
}
|
|
1170
|
+
else {
|
|
1171
|
+
str += link;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
if (address.group) {
|
|
1175
|
+
str += formatSingleLevel(address.group) + ';';
|
|
1176
|
+
}
|
|
1177
|
+
return str + '</span>';
|
|
1178
|
+
})
|
|
1179
|
+
.join(', ');
|
|
1235
1180
|
return formatSingleLevel([].concat(value || []));
|
|
1236
1181
|
}
|
|
1237
|
-
|
|
1182
|
+
/**
|
|
1183
|
+
* Formats parsed addresses as plain text, display names quoted.
|
|
1184
|
+
*/
|
|
1238
1185
|
getAddressesText(value) {
|
|
1239
|
-
let formatSingleLevel = addresses =>
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1186
|
+
let formatSingleLevel = (addresses) => addresses
|
|
1187
|
+
.map(address => {
|
|
1188
|
+
let str = '';
|
|
1189
|
+
if (address.name) {
|
|
1190
|
+
// a quoted-string, so a quote or backslash inside the name is escaped
|
|
1191
|
+
str += `"${address.name.replace(/["\\]/g, '\\$&')}"` + (address.group ? ': ' : '');
|
|
1192
|
+
}
|
|
1193
|
+
if (address.address) {
|
|
1194
|
+
let link = address.address;
|
|
1195
|
+
if (address.name) {
|
|
1196
|
+
str += ' <' + link + '>';
|
|
1197
|
+
}
|
|
1198
|
+
else {
|
|
1199
|
+
str += link;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
if (address.group) {
|
|
1203
|
+
str += formatSingleLevel(address.group) + ';';
|
|
1204
|
+
}
|
|
1205
|
+
return str;
|
|
1206
|
+
})
|
|
1207
|
+
.join(', ');
|
|
1261
1208
|
return formatSingleLevel([].concat(value || []));
|
|
1262
1209
|
}
|
|
1263
|
-
|
|
1210
|
+
/**
|
|
1211
|
+
* Replaces `cid:` links to image attachments in the HTML content. Call it once the parser has
|
|
1212
|
+
* ended. `replaceCallback` is called once for every referenced image attachment and answers with
|
|
1213
|
+
* the URL to use instead; `done` gets the updated HTML, or `false` when the message has no HTML.
|
|
1214
|
+
* The total length of the URLs written is bounded by `maxInlinedImagesSize`.
|
|
1215
|
+
*/
|
|
1264
1216
|
updateImageLinks(replaceCallback, done) {
|
|
1265
1217
|
if (!this.html) {
|
|
1266
|
-
|
|
1218
|
+
setImmediate(() => done(null, false));
|
|
1219
|
+
return;
|
|
1267
1220
|
}
|
|
1268
|
-
|
|
1269
1221
|
let cids = new Map();
|
|
1270
1222
|
let html = (this.html || '').toString();
|
|
1271
|
-
|
|
1272
1223
|
if (this.options.skipImageLinks) {
|
|
1273
1224
|
return done(null, html);
|
|
1274
1225
|
}
|
|
1275
|
-
|
|
1276
1226
|
html.replace(/\bcid:([^'"\s]{1,256})/g, (match, cid) => {
|
|
1277
1227
|
for (let i = 0, len = this.attachmentList.length; i < len; i++) {
|
|
1278
1228
|
if (this.attachmentList[i].cid === cid && /^image\/[\w]+$/i.test(this.attachmentList[i].contentType)) {
|
|
@@ -1284,12 +1234,10 @@ class MailParser extends Transform {
|
|
|
1284
1234
|
}
|
|
1285
1235
|
return match;
|
|
1286
1236
|
});
|
|
1287
|
-
|
|
1288
1237
|
let cidList = [];
|
|
1289
1238
|
cids.forEach(entry => {
|
|
1290
1239
|
cidList.push(entry);
|
|
1291
1240
|
});
|
|
1292
|
-
|
|
1293
1241
|
let pos = 0;
|
|
1294
1242
|
let processNext = () => {
|
|
1295
1243
|
if (pos >= cidList.length) {
|
|
@@ -1311,36 +1259,35 @@ class MailParser extends Transform {
|
|
|
1311
1259
|
inlinedSize += url.length;
|
|
1312
1260
|
return url;
|
|
1313
1261
|
});
|
|
1314
|
-
}
|
|
1262
|
+
}
|
|
1263
|
+
catch (err) {
|
|
1315
1264
|
// runs from setImmediate, a throw here would be an uncaught exception
|
|
1316
1265
|
return done(err);
|
|
1317
1266
|
}
|
|
1318
|
-
|
|
1319
1267
|
return done(null, html);
|
|
1320
1268
|
}
|
|
1321
1269
|
let entry = cidList[pos++];
|
|
1322
1270
|
replaceCallback(entry.attachment, (err, url) => {
|
|
1323
1271
|
if (err) {
|
|
1324
|
-
|
|
1272
|
+
setImmediate(() => done(err));
|
|
1273
|
+
return;
|
|
1325
1274
|
}
|
|
1326
1275
|
entry.url = url;
|
|
1327
1276
|
setImmediate(processNext);
|
|
1328
1277
|
});
|
|
1329
1278
|
};
|
|
1330
|
-
|
|
1331
1279
|
setImmediate(processNext);
|
|
1332
1280
|
}
|
|
1333
|
-
|
|
1334
1281
|
// Tells whether a text segment is worth handing to linkify-it, see
|
|
1335
1282
|
// MAX_LINKIFY_* above. Note that linkify.pretest() can not be used for this
|
|
1336
1283
|
// - it is a quick deny that also denies links its own matcher finds, eg. a
|
|
1337
1284
|
// host followed by a fullwidth vertical bar.
|
|
1285
|
+
/** @internal */
|
|
1338
1286
|
canScanSegment(segment) {
|
|
1339
1287
|
// every link linkify-it can find contains at least one of these
|
|
1340
1288
|
if (segment.length > MAX_LINKIFY_SEGMENT_LENGTH || !/[.:@/]/.test(segment)) {
|
|
1341
1289
|
return false;
|
|
1342
1290
|
}
|
|
1343
|
-
|
|
1344
1291
|
// Dots only chain up into one host candidate while the characters
|
|
1345
1292
|
// around them could be part of a host, so a slash, comma or colon ends
|
|
1346
1293
|
// the chain and dots in a path or query do not add to it.
|
|
@@ -1351,21 +1298,19 @@ class MailParser extends Transform {
|
|
|
1351
1298
|
if (++labels > MAX_LINKIFY_HOST_LABELS) {
|
|
1352
1299
|
return false;
|
|
1353
1300
|
}
|
|
1354
|
-
}
|
|
1301
|
+
}
|
|
1302
|
+
else if (!isHostChar(code)) {
|
|
1355
1303
|
labels = 0;
|
|
1356
1304
|
}
|
|
1357
1305
|
}
|
|
1358
|
-
|
|
1359
1306
|
return true;
|
|
1360
1307
|
}
|
|
1361
|
-
|
|
1308
|
+
/** @internal */
|
|
1362
1309
|
findLinks(str) {
|
|
1363
1310
|
let links = [];
|
|
1364
|
-
|
|
1365
1311
|
if (this.linkifyWork >= MAX_LINKIFY_WORK || !linkify.pretest(str)) {
|
|
1366
1312
|
return links;
|
|
1367
1313
|
}
|
|
1368
|
-
|
|
1369
1314
|
// Whitespace can not be part of a link and linkify-it treats the end of
|
|
1370
1315
|
// a segment exactly like whitespace, so scanning segment by segment
|
|
1371
1316
|
// finds the same links as scanning the entire string would. U+FEFF is
|
|
@@ -1373,89 +1318,80 @@ class MailParser extends Transform {
|
|
|
1373
1318
|
// linkify-it, so it must not end a segment.
|
|
1374
1319
|
let segmentRegex = /[\S\uFEFF]+/g;
|
|
1375
1320
|
let segmentMatch;
|
|
1376
|
-
|
|
1377
1321
|
while ((segmentMatch = segmentRegex.exec(str)) !== null) {
|
|
1378
1322
|
let segment = segmentMatch[0];
|
|
1379
|
-
|
|
1380
1323
|
if (!this.canScanSegment(segment)) {
|
|
1381
1324
|
// too expensive to scan or can not match at all, keep as plain text
|
|
1382
1325
|
continue;
|
|
1383
1326
|
}
|
|
1384
|
-
|
|
1385
1327
|
let matches = linkify.match(segment);
|
|
1386
1328
|
for (let i = 0; matches && i < matches.length; i++) {
|
|
1387
1329
|
matches[i].index += segmentMatch.index;
|
|
1388
1330
|
matches[i].lastIndex += segmentMatch.index;
|
|
1389
1331
|
links.push(matches[i]);
|
|
1390
1332
|
}
|
|
1391
|
-
|
|
1392
1333
|
this.linkifyWork += segment.length * (segment.length + 1024);
|
|
1393
1334
|
if (this.linkifyWork >= MAX_LINKIFY_WORK) {
|
|
1394
1335
|
break;
|
|
1395
1336
|
}
|
|
1396
1337
|
}
|
|
1397
|
-
|
|
1398
1338
|
return links;
|
|
1399
1339
|
}
|
|
1400
|
-
|
|
1340
|
+
/**
|
|
1341
|
+
* Converts plain text to HTML the way `textAsHtml` is built: HTML-escaped, paragraphs and line
|
|
1342
|
+
* breaks kept, and links turned into anchors unless `skipTextLinks` is set. Returns an empty
|
|
1343
|
+
* string when `skipTextToHtml` is set.
|
|
1344
|
+
*/
|
|
1401
1345
|
textToHtml(str) {
|
|
1402
1346
|
if (this.options.skipTextToHtml) {
|
|
1403
1347
|
return '';
|
|
1404
1348
|
}
|
|
1405
1349
|
str = (str || '').toString();
|
|
1406
1350
|
let encoded;
|
|
1407
|
-
|
|
1408
1351
|
if (!this.options.skipTextLinks) {
|
|
1409
1352
|
try {
|
|
1410
1353
|
let links = this.findLinks(str);
|
|
1411
1354
|
if (links.length) {
|
|
1412
1355
|
let result = [];
|
|
1413
1356
|
let last = 0;
|
|
1414
|
-
|
|
1415
1357
|
links.forEach(link => {
|
|
1416
1358
|
if (last < link.index) {
|
|
1417
1359
|
let textPart = he
|
|
1418
1360
|
// encode special chars
|
|
1419
1361
|
.encode(str.slice(last, link.index), {
|
|
1420
|
-
|
|
1421
|
-
|
|
1362
|
+
useNamedReferences: true
|
|
1363
|
+
});
|
|
1422
1364
|
result.push(textPart);
|
|
1423
1365
|
}
|
|
1424
|
-
|
|
1425
1366
|
// Escape quotes in URL to prevent XSS
|
|
1426
1367
|
let safeUrl = link.url.replace(/"/g, '"');
|
|
1427
1368
|
// Escape HTML entities in link text
|
|
1428
1369
|
let safeText = he.encode(link.text, { useNamedReferences: true });
|
|
1429
1370
|
result.push(`<a href="${safeUrl}">${safeText}</a>`);
|
|
1430
|
-
|
|
1431
1371
|
last = link.lastIndex;
|
|
1432
1372
|
});
|
|
1433
|
-
|
|
1434
1373
|
let textPart = he
|
|
1435
1374
|
// encode special chars
|
|
1436
1375
|
.encode(str.slice(last), {
|
|
1437
|
-
|
|
1438
|
-
|
|
1376
|
+
useNamedReferences: true
|
|
1377
|
+
});
|
|
1439
1378
|
result.push(textPart);
|
|
1440
|
-
|
|
1441
1379
|
encoded = result.join('');
|
|
1442
1380
|
}
|
|
1443
|
-
}
|
|
1381
|
+
}
|
|
1382
|
+
catch {
|
|
1444
1383
|
// failed, don't linkify
|
|
1445
1384
|
}
|
|
1446
1385
|
}
|
|
1447
|
-
|
|
1448
1386
|
// nothing linkified, or linkifying threw halfway through
|
|
1449
1387
|
if (!encoded) {
|
|
1450
1388
|
encoded = he
|
|
1451
1389
|
// encode special chars
|
|
1452
1390
|
.encode(str, {
|
|
1453
|
-
|
|
1454
|
-
|
|
1391
|
+
useNamedReferences: true
|
|
1392
|
+
});
|
|
1455
1393
|
}
|
|
1456
|
-
|
|
1457
|
-
let text =
|
|
1458
|
-
'<p>' +
|
|
1394
|
+
let text = '<p>' +
|
|
1459
1395
|
encoded
|
|
1460
1396
|
.replace(/\r?\n/g, '\n')
|
|
1461
1397
|
.trim() // normalize line endings
|
|
@@ -1470,9 +1406,7 @@ class MailParser extends Transform {
|
|
|
1470
1406
|
.trim() // insert <p> to multiple linebreaks
|
|
1471
1407
|
.replace(/\n/g, '<br/>') + // insert <br> to single linebreaks
|
|
1472
1408
|
'</p>';
|
|
1473
|
-
|
|
1474
1409
|
return text;
|
|
1475
1410
|
}
|
|
1476
1411
|
}
|
|
1477
|
-
|
|
1478
|
-
module.exports = MailParser;
|
|
1412
|
+
export default MailParser;
|