Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 2.2.0
* Maintenance fork of `enough_mail`
* Fix: Prevent header folding immediately after opening angle bracket `<` in `From` and other headers to avoid SpamAssassin errors.

# 2.1.7
* chore: Update plugin and dependencies versions - thanks to [Dr-Usman](https://github.com/Dr-Usman)!
* chore: pub upgrade to bring in intl 0.20.2 - thanks to [jpohhhh](https://github.com/jpohhhh)!
Expand Down Expand Up @@ -72,7 +76,7 @@ OauthAuthentication now contains a complete OauthToken.
* Simplify search API.

Breaking changes:
* Package structure is simplified, so that imports of specific classes are not possible anymore. Instead either `import 'package:enough_mail/enough_mail.dart';` or one of the specializes sub-packages `codecs.dart`,`discover.dart`, `highlevel.dart`, `imap.dart`, `mime.dart`, `pop.dart` or `smtp.dart`.
* Package structure is simplified, so that imports of specific classes are not possible anymore. Instead either `import 'package:enough_mail_plus/enough_mail.dart';` or one of the specializes sub-packages `codecs.dart`,`discover.dart`, `highlevel.dart`, `imap.dart`, `mime.dart`, `pop.dart` or `smtp.dart`.
* `Authentication.passwordCleartext` is renamed to `Authentication.passwordClearText`
* `Mailbox` API has changed specifically when creating mailboxes yourself.

Expand Down Expand Up @@ -300,7 +304,7 @@ Other:
## 0.0.30
- Thanks to [hpoul](https://github.com/hpoul) the XML library now works with both beta and stable flutter channels.
- Thanks to [hydeparkk](https://github.com/hydeparkk) encoded mailbox paths are now used in copy, move, status and append/
- Fix decoding message date headers
- Fix decoding bug for UTF8 8 bit encoded text
- Fix handling mailboxes with a space in their path
- Allow to easly serialize and deserialize [MailAccount](https://pub.dev/documentation/enough_mail/latest/mail_mail_account/MailAccount-class.html) to/from JSON.
- Extended high level [MailClient API](https://pub.dev/documentation/enough_mail/latest/mail_mail_client/MailClient-class.html):
Expand Down
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
# enough_mail_plus

**Maintenance fork of [enough_mail](https://pub.dev/packages/enough_mail)**

IMAP, POP3 and SMTP clients for Dart and Flutter email developers.

Available under the commercial friendly
[MPL Mozilla Public License 2.0](https://www.mozilla.org/en-US/MPL/).

## Key Fixes in this Fork
* **Header Folding Fix**: Prevents invalid folding after `<` in headers, resolving common SpamAssassin errors like "Leading whitespace after '<'" and "unbalanced angle brackets".

## Installation
Add this dependency your pubspec.yaml file:

```
```yaml
dependencies:
enough_mail: ^2.1.7
enough_mail_plus: ^2.2.0
```
The latest version or `enough_mail` is [![enough_mail version](https://img.shields.io/pub/v/enough_mail.svg)](https://pub.dartlang.org/packages/enough_mail).


## API Documentation
Check out the full API documentation at https://pub.dev/documentation/enough_mail/latest/
Check out the full API documentation at https://pub.dev/documentation/enough_mail_plus/latest/


## High Level API Usage

Expand All @@ -24,7 +29,7 @@ A simple usage example for using the high level API:

```dart
import 'dart:io';
import 'package:enough_mail/enough_mail.dart';
import 'package:enough_mail_plus/enough_mail.dart';

String userName = 'user.name';
String password = 'password';
Expand Down Expand Up @@ -112,7 +117,7 @@ A simple usage example for using the low level API:

```dart
import 'dart:io';
import 'package:enough_mail/enough_mail.dart';
import 'package:enough_mail_plus/enough_mail.dart';

String userName = 'user.name';
String password = 'password';
Expand Down
2 changes: 1 addition & 1 deletion example/discover.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'dart:io';

import 'package:enough_mail/discover.dart';
import 'package:enough_mail_plus/discover.dart';

// ignore: avoid_void_async
void main(List<String> args) async {
Expand Down
2 changes: 1 addition & 1 deletion example/enough_mail_example.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'dart:io';

import 'package:enough_mail/enough_mail.dart';
import 'package:enough_mail_plus/enough_mail.dart';

String userName = 'user.name';
String password = 'password';
Expand Down
3 changes: 1 addition & 2 deletions lib/src/discover/client_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -350,8 +350,7 @@ class ServerConfig {
return email.substring(lastAtIndex + 1);
case UsernameType.realName:
case UsernameType.unknown:
default:
return null;
return null;
}
}

Expand Down
85 changes: 62 additions & 23 deletions lib/src/mime_message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1344,50 +1344,89 @@ class Header {
/// Renders this header into a the [buffer] wrapping it if necessary.
void render(StringBuffer buffer) {
final value = this.value;
var length = name.length + ': '.length + (value?.length ?? 0);
if (value == null) {
buffer
..write(name)
..write(': \r\n');

return;
}
final totalLength = value.length;
var currentLineLength = name.length + ': '.length;
buffer
..write(name)
..write(': ');
if (value == null || length < MailConventions.textLineMaxLength) {
if (value != null) {
buffer.write(value);
}
buffer.write('\r\n');
if (currentLineLength + totalLength < MailConventions.textLineMaxLength) {
buffer
..write(value)
..write('\r\n');

return;
}
var currentLineLength = name.length + ': '.length;
length -= name.length + ': '.length;
final runes = value.runes.toList();
var startIndex = 0;
while (length > 0) {
while (startIndex < totalLength) {
var chunkLength = MailConventions.textLineMaxLength - currentLineLength;
if (startIndex + chunkLength >= value.length) {
if (startIndex + chunkLength >= totalLength) {
// write reminder:
buffer
..write(value.substring(startIndex).trim())
..write('\r\n');
break;
}
for (var runeIndex = startIndex + chunkLength;
runeIndex > startIndex;
runeIndex--) {
final rune = runes[runeIndex];
if (rune == AsciiRunes.runeSemicolon ||
rune == AsciiRunes.runeSpace ||
rune == AsciiRunes.runeClosingParentheses ||
rune == AsciiRunes.runeClosingBracket ||
rune == AsciiRunes.runeGreaterThan) {
chunkLength = runeIndex - startIndex + 1;
var foundFoldingPoint = false;
for (var i = startIndex + chunkLength; i > startIndex; i--) {
final char = value.codeUnitAt(i);
if (char == AsciiRunes.runeSemicolon ||
char == AsciiRunes.runeSpace ||
char == AsciiRunes.runeClosingParentheses ||
char == AsciiRunes.runeClosingBracket ||
char == AsciiRunes.runeGreaterThan ||
char == AsciiRunes.runeComma) {
chunkLength = i - startIndex + 1;
foundFoldingPoint = true;
break;
}
}
if (!foundFoldingPoint) {
// try to find a folding point after chunkLength
// up to messageLineMaxLength
for (var i = startIndex + chunkLength + 1; i < totalLength; i++) {
if (currentLineLength + (i - startIndex) >=
MailConventions.messageLineMaxLength) {
chunkLength = i - startIndex;
// avoid splitting surrogate pairs
if (chunkLength > 0 &&
value.codeUnitAt(startIndex + chunkLength - 1) >= 0xD800 &&
value.codeUnitAt(startIndex + chunkLength - 1) <= 0xDBFF) {
chunkLength--;
}
break;
}
final char = value.codeUnitAt(i);
if (char == AsciiRunes.runeSemicolon ||
char == AsciiRunes.runeSpace ||
char == AsciiRunes.runeClosingParentheses ||
char == AsciiRunes.runeClosingBracket ||
char == AsciiRunes.runeGreaterThan ||
char == AsciiRunes.runeComma) {
chunkLength = i - startIndex + 1;
foundFoldingPoint = true;
break;
}
}
if (!foundFoldingPoint && startIndex + chunkLength < totalLength) {
// check if we can just take the rest of the string if it's under 998:
if (currentLineLength + (totalLength - startIndex) <
MailConventions.messageLineMaxLength) {
chunkLength = totalLength - startIndex;
}
}
}
buffer
..write(value.substring(startIndex, startIndex + chunkLength).trim())
..write('\r\n');
length -= chunkLength;
startIndex += chunkLength;
if (length > 0) {
if (startIndex < totalLength) {
buffer.writeCharCode(AsciiRunes.runeTab);
currentLineLength = 1;
}
Expand Down
14 changes: 7 additions & 7 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: enough_mail
description: IMAP, POP3 and SMTP for email developers. Choose between a low
level and a high level API for mailing. Parse and generate MIME messages.
Discover email settings.
version: 2.1.7
homepage: https://github.com/Enough-Software/enough_mail
name: enough_mail_plus
description: Maintenance fork of enough_mail. IMAP, POP3 and SMTP for email
developers. Choose between a low level and a high level API for mailing.
Parse and generate MIME messages. Discover email settings.
version: 2.2.0
repository: https://github.com/nogringo/enough_mail
topics:
- email
- imap
Expand All @@ -23,7 +23,7 @@ dependencies:
encrypter_plus: ^5.1.0
enough_convert: ^1.6.0
event_bus: ^2.0.1
intl: any
intl: ^0.20.2
json_annotation: ^4.9.0
pointycastle: ^4.0.0
synchronized: ^3.4.0
Expand Down
2 changes: 1 addition & 1 deletion test/codecs/base64_mail_codec_test.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'dart:convert';

import 'package:enough_mail/src/codecs/mail_codec.dart';
import 'package:enough_mail_plus/src/codecs/mail_codec.dart';
import 'package:test/test.dart';
// cSpell:disable

Expand Down
2 changes: 1 addition & 1 deletion test/codecs/date_codec_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:enough_mail/src/codecs/date_codec.dart';
import 'package:enough_mail_plus/src/codecs/date_codec.dart';
import 'package:test/test.dart';
import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
Expand Down
8 changes: 4 additions & 4 deletions test/codecs/folding_test.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:enough_mail/src/codecs/mail_codec.dart';
import 'package:enough_mail/src/mail_address.dart';
import 'package:enough_mail/src/message_builder.dart';
import 'package:enough_mail/src/mime_message.dart';
import 'package:enough_mail_plus/src/codecs/mail_codec.dart';
import 'package:enough_mail_plus/src/mail_address.dart';
import 'package:enough_mail_plus/src/message_builder.dart';
import 'package:enough_mail_plus/src/mime_message.dart';
import 'package:test/test.dart';
// cSpell:disable

Expand Down
2 changes: 1 addition & 1 deletion test/codecs/mail_codec_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:enough_mail/src/codecs/mail_codec.dart';
import 'package:enough_mail_plus/src/codecs/mail_codec.dart';
import 'package:test/test.dart';
// cSpell:disable

Expand Down
2 changes: 1 addition & 1 deletion test/codecs/modified_utf7_codec_test.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'dart:convert';

import 'package:enough_mail/src/codecs/modified_utf7_codec.dart';
import 'package:enough_mail_plus/src/codecs/modified_utf7_codec.dart';
import 'package:test/test.dart';

void main() {
Expand Down
2 changes: 1 addition & 1 deletion test/codecs/quoted_printable_mail_codec_test.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'dart:convert' as convert;

import 'package:enough_mail/src/codecs/mail_codec.dart';
import 'package:enough_mail_plus/src/codecs/mail_codec.dart';
import 'package:test/test.dart';
// cSpell:disable

Expand Down
17 changes: 17 additions & 0 deletions test/folding_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'package:enough_mail_plus/enough_mail.dart';
import 'package:test/test.dart';

void main() {
test('Should not fold long email address in From header', () {
const longEmail =
'npub1mlfgj95gv89tdjemt2jc4jqvn4dumhujeymzv20ljqywcfupwz5s09pe55@testnm'
'ail.uid.ovh';

final builder = MessageBuilder()
..from = [const MailAddress('Test', longEmail)];
final mimeMessage = builder.buildMimeMessage();
final rendered = mimeMessage.renderMessage();

expect(rendered, contains('<$longEmail>'));
});
}
4 changes: 2 additions & 2 deletions test/imap/imap_client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import 'dart:async';
import 'dart:io' show Platform;

import 'package:enough_mail/enough_mail.dart';
import 'package:enough_mail/src/private/util/client_base.dart';
import 'package:enough_mail_plus/enough_mail.dart';
import 'package:enough_mail_plus/src/private/util/client_base.dart';
import 'package:event_bus/event_bus.dart';
import 'package:test/test.dart';

Expand Down
2 changes: 1 addition & 1 deletion test/imap/mailbox_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:enough_mail/src/imap/mailbox.dart';
import 'package:enough_mail_plus/src/imap/mailbox.dart';
import 'package:test/test.dart';
// cSpell:disable

Expand Down
4 changes: 2 additions & 2 deletions test/imap/message_sequence_test.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:enough_mail/src/exception.dart';
import 'package:enough_mail/src/imap/message_sequence.dart';
import 'package:enough_mail_plus/src/exception.dart';
import 'package:enough_mail_plus/src/imap/message_sequence.dart';
import 'package:test/test.dart';

void main() {
Expand Down
2 changes: 1 addition & 1 deletion test/imap/qresync_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:enough_mail/enough_mail.dart';
import 'package:enough_mail_plus/enough_mail.dart';
import 'package:test/test.dart';
// cSpell:disable

Expand Down
2 changes: 1 addition & 1 deletion test/imap/response_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:enough_mail/enough_mail.dart';
import 'package:enough_mail_plus/enough_mail.dart';
import 'package:test/test.dart';
// cSpell:disable

Expand Down
2 changes: 1 addition & 1 deletion test/mail/mail_account_test.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'dart:convert';

import 'package:enough_mail/enough_mail.dart';
import 'package:enough_mail_plus/enough_mail.dart';
import 'package:test/test.dart';

void main() {
Expand Down
2 changes: 1 addition & 1 deletion test/mail/results_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:enough_mail/enough_mail.dart';
import 'package:enough_mail_plus/enough_mail.dart';
import 'package:test/test.dart';

void main() {
Expand Down
12 changes: 6 additions & 6 deletions test/message_builder_test.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import 'dart:io';
import 'dart:typed_data';

import 'package:enough_mail/src/mail_address.dart';
import 'package:enough_mail/src/mail_conventions.dart';
import 'package:enough_mail/src/media_type.dart';
import 'package:enough_mail/src/message_builder.dart';
import 'package:enough_mail/src/mime_data.dart';
import 'package:enough_mail/src/mime_message.dart';
import 'package:enough_mail_plus/src/mail_address.dart';
import 'package:enough_mail_plus/src/mail_conventions.dart';
import 'package:enough_mail_plus/src/media_type.dart';
import 'package:enough_mail_plus/src/message_builder.dart';
import 'package:enough_mail_plus/src/mime_data.dart';
import 'package:enough_mail_plus/src/mime_message.dart';
import 'package:test/test.dart';
// cSpell:disable

Expand Down
Loading