Skip to content
Merged
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
21 changes: 19 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
# 2.2.3
* Chore: Shorten package description to 60-180 characters for pub.dev score
* Docs: Add example file (example/example.dart)
* Fix: Resolve dangling library doc comments in all library files
* Fix: Replace angle brackets with placeholders in documentation comments
* Chore: Format all Dart files with dart format

# 2.2.2
* Fix: `removeHeader()` now correctly removes headers from rendered messages. Previously, headers modified via `removeHeader()`, `setHeader()`, or `addHeader()` were not reflected in `renderMessage()` output because the render method used original mimeData instead of modified headers.

# 2.2.1
* Fix: Tolerate bare LF (`\n`) line endings in MIME parsing. RFC 5322 mandates CRLF but some generators (e.g. Node.js mimetext on Linux) produce bare LF. This caused missing subjects and headers when parsing such MIME.

# 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 +89,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 +317,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
52 changes: 52 additions & 0 deletions example/example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import 'package:enough_mail_plus/enough_mail.dart';

/// Simple example demonstrating basic email discovery and IMAP usage.
void main() async {
// Auto-discover email settings
const email = 'user@example.com';
final config = await Discover.discover(email, isLogEnabled: false);

if (config == null) {
print('Unable to discover settings for $email');
return;
}

print('Found settings for $email:');
for (final provider in config.emailProviders ?? []) {
print('Provider: ${provider.displayName}');
print('Domains: ${provider.domains}');
}

// IMAP example
final imapClient = ImapClient(isLogEnabled: false);
await imapClient.connectToServer('imap.example.com', 993, isSecure: true);
await imapClient.login('user@example.com', 'password');
await imapClient.selectInbox();

final messages = await imapClient.fetchRecentMessages(messageCount: 5);
for (final message in messages.messages) {
print('From: ${message.from}');
print('Subject: ${message.decodeSubject()}');
}

await imapClient.logout();

// SMTP example
final smtpClient = SmtpClient('example.com', isLogEnabled: false);
await smtpClient.connectToServer('smtp.example.com', 587, isSecure: false);
await smtpClient.ehlo();
if (smtpClient.serverInfo.supportsAuth(AuthMechanism.plain)) {
await smtpClient.authenticate(
'user@example.com', 'password', AuthMechanism.plain);
}

final builder = MessageBuilder()
..from = [const MailAddress('Sender', 'sender@example.com')]
..to = [const MailAddress('Recipient', 'recipient@example.com')]
..subject = 'Test Email'
..text = 'Hello from enough_mail_plus!';

final message = builder.buildMimeMessage();
await smtpClient.sendMessage(message);
print('Email sent successfully!');
}
2 changes: 2 additions & 0 deletions lib/codecs.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
library codecs;

/// Email codec classes
export 'mime.dart';
export 'src/codecs/base64_mail_codec.dart';
Expand Down
3 changes: 2 additions & 1 deletion lib/discover.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/// Discovers email settings based on an email address.
library discover;

/// Discovers email settings based on an email address.
export 'src/discover/client_config.dart';
export 'src/discover/discover.dart';
2 changes: 2 additions & 0 deletions lib/highlevel.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
library highlevel;

/// Highlevel email API
///
/// Start with `MailClient` to connect to any mail service.
Expand Down
2 changes: 2 additions & 0 deletions lib/imap.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
library imap;

/// Anything you need to fetch and process messages using the IMAP protocol.
///
/// Use the `ImapClient` to connect to any IMAP compliant service.
Expand Down
2 changes: 2 additions & 0 deletions lib/mime.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
library mime;

/// Base email classes
export 'src/exception.dart';
export 'src/imap/message_sequence.dart';
Expand Down
3 changes: 2 additions & 1 deletion lib/pop.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
library pop;

/// Fetch messages using the POP3 protocol
///
/// Start with the `PopClient` to connect to a POP3 enabled service.

export 'mime.dart';
export 'src/pop/pop_client.dart';
export 'src/pop/pop_events.dart';
Expand Down
2 changes: 2 additions & 0 deletions lib/smtp.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
library smtp;

/// Everything you need to send messages using the SMTP protocol.
///
/// With the `SmtpClient` you can connect to any SMTP service.
Expand Down
1 change: 0 additions & 1 deletion lib/src/discover/client_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,6 @@ class ServerConfig {
return email.substring(lastAtIndex + 1);
case UsernameType.realName:
case UsernameType.unknown:
default:
return null;
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/src/message_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ class MessageBuilder extends PartBuilder {
///
/// You can also specify a custom [replyHeaderTemplate], which is only used
/// when [quoteOriginalText] has been set to true. The default
/// replyHeaderTemplate is 'On <date> <from> wrote:'.
/// replyHeaderTemplate is 'On {date} {from} wrote:'.
///
/// Set [replyToSimplifyReferences] to true if the References field
/// should not contain the references of all messages in this thread.
Expand Down
15 changes: 12 additions & 3 deletions lib/src/mime_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,20 @@ class TextMimeData extends MimeData {
/// Creates a new text based mime data
///
/// with the specified [text] and the [containsHeader] information.
TextMimeData(this.text, {required bool containsHeader})
: super(containsHeader: containsHeader) {
_size = text.length;
///
/// Line endings are automatically normalized to CRLF (`\r\n`) for
/// RFC 5322 compliance, tolerating bare LF from non-conformant MIME
/// generators (e.g. Node.js mimetext on Linux which uses `os.EOL`).
TextMimeData(String text, {required bool containsHeader})
: text = _normalizeLineEndings(text),
super(containsHeader: containsHeader) {
_size = this.text.length;
}

/// Normalizes bare LF to CRLF for RFC 5322 compliance.
static String _normalizeLineEndings(String text) =>
text.replaceAll(RegExp(r'(?<!\r)\n'), '\r\n');

/// The text representation of the full mime data
final String text;

Expand Down
Loading
Loading