Always move sent messages to the sent folder (if any)

pull/147/head
M66B 6 years ago
parent bd1c741f2e
commit fc87b37b20

@ -68,7 +68,7 @@ FairEmail follows all the best practices for an email client as decribed in [thi
* [(4) How can I use an invalid security certificate / IMAP STARTTLS / an empty password?](#user-content-faq4) * [(4) How can I use an invalid security certificate / IMAP STARTTLS / an empty password?](#user-content-faq4)
* [(5) How can I customize the message view?](#user-content-faq5) * [(5) How can I customize the message view?](#user-content-faq5)
* [(6) How can I login to Gmail / G suite?](#user-content-faq6) * [(6) How can I login to Gmail / G suite?](#user-content-faq6)
* [(7) Why are messages in the outbox not moved to the sent folder?](#user-content-faq7) * [~~(7) Why are messages in the outbox not moved to the sent folder?~~](#user-content-faq7)
* [(8) Can I use a Microsoft Exchange account?](#user-content-faq8) * [(8) Can I use a Microsoft Exchange account?](#user-content-faq8)
* [(9) What are identities?](#user-content-faq9) * [(9) What are identities?](#user-content-faq9)
* [(11) Why is POP not supported?](#user-content-faq11) * [(11) Why is POP not supported?](#user-content-faq11)
@ -246,13 +246,13 @@ If this doesn't work, see here for more solutions: [https://support.google.com/m
<br /> <br />
<a name="faq7"></a> <a name="faq7"></a>
**(7) Why are messages in the outbox not moved to the sent folder?** **~~(7) Why are messages in the outbox not moved to the sent folder?~~**
Messages in the outbox are moved to the sent folder as soon as your provider adds the message to the sent folder. ~~Messages in the outbox are moved to the sent folder as soon as your provider adds the message to the sent folder.
Note that this requires a sent folder to be selected and to be set to synchronizing. Note that this requires a sent folder to be selected and to be set to synchronizing.
If this doesn't happen, your provider might not keep track of sent messages or you might be using an SMTP server not related to the provider. If this doesn't happen, your provider might not keep track of sent messages or you might be using an SMTP server not related to the provider.
In these cases you can use the advanced identity setting *Store a copy of sent messages in* and select the sent folder. In these cases you can use the advanced identity setting *Store a copy of sent messages in* and select the sent folder.
There is a menu to move sent messages in the outbox to the sent folder. There is a menu to move sent messages in the outbox to the sent folder.~~
<br /> <br />
@ -983,6 +983,8 @@ Messages shown dimmed are locally moved messages for which the move is not confi
This can happen when there is no connection with the server or when the messages are too old to be synchronized. This can happen when there is no connection with the server or when the messages are too old to be synchronized.
Eventually, these messages will be synchronized when the connection to the server is restored or will be deleted if they are too old to be synchronized. Eventually, these messages will be synchronized when the connection to the server is restored or will be deleted if they are too old to be synchronized.
Some providers don't store sent messages, in this case messages in the sent folder might never be synchronized.
You can view these messages, but you cannot move these messages again until the previous move has been confirmed by the server. You can view these messages, but you cannot move these messages again until the previous move has been confirmed by the server.
<br /> <br />

@ -296,6 +296,9 @@ public interface DaoMessage {
@Query("UPDATE message SET ui_ignored = :ui_ignored WHERE id = :id") @Query("UPDATE message SET ui_ignored = :ui_ignored WHERE id = :id")
int setMessageUiIgnored(long id, boolean ui_ignored); int setMessageUiIgnored(long id, boolean ui_ignored);
@Query("UPDATE message SET sent = :sent WHERE id = :id")
int setMessageSent(long id, Long sent);
@Query("UPDATE message SET warning = :warning WHERE id = :id") @Query("UPDATE message SET warning = :warning WHERE id = :id")
int setMessageWarning(long id, String warning); int setMessageWarning(long id, String warning);

@ -81,7 +81,7 @@ public class EntityIdentity {
public Boolean read_receipt; public Boolean read_receipt;
@NonNull @NonNull
public Boolean store_sent = false; // obsolete public Boolean store_sent = false; // obsolete
public Long sent_folder; public Long sent_folder; // obsolete
public Boolean tbd; public Boolean tbd;
public String state; public String state;
public String error; public String error;
@ -109,9 +109,6 @@ public class EntityIdentity {
json.put("bcc", bcc); json.put("bcc", bcc);
json.put("delivery_receipt", delivery_receipt); json.put("delivery_receipt", delivery_receipt);
json.put("read_receipt", read_receipt); json.put("read_receipt", read_receipt);
json.put("store_sent", store_sent);
if (sent_folder != null)
json.put("sent_folder", sent_folder);
// not state // not state
// not error // not error
return json; return json;
@ -157,12 +154,6 @@ public class EntityIdentity {
else else
identity.read_receipt = false; identity.read_receipt = false;
if (json.has("store_sent"))
identity.store_sent = json.getBoolean("store_sent");
if (json.has("sent_folder"))
identity.sent_folder = json.getLong("sent_folder");
return identity; return identity;
} }
@ -187,7 +178,6 @@ public class EntityIdentity {
(this.replyto == null ? other.replyto == null : this.replyto.equals(other.replyto)) && (this.replyto == null ? other.replyto == null : this.replyto.equals(other.replyto)) &&
this.delivery_receipt.equals(other.delivery_receipt) && this.delivery_receipt.equals(other.delivery_receipt) &&
this.read_receipt.equals(other.read_receipt) && this.read_receipt.equals(other.read_receipt) &&
(this.sent_folder == null ? other.sent_folder == null : this.sent_folder.equals(other.sent_folder)) &&
(this.tbd == null ? other.tbd == null : this.tbd.equals(other.tbd)) && (this.tbd == null ? other.tbd == null : this.tbd.equals(other.tbd)) &&
(this.state == null ? other.state == null : this.state.equals(other.state)) && (this.state == null ? other.state == null : this.state.equals(other.state)) &&
(this.error == null ? other.error == null : this.error.equals(other.error))); (this.error == null ? other.error == null : this.error.equals(other.error)));

@ -110,7 +110,6 @@ public class FragmentIdentity extends FragmentBase {
private EditText etBcc; private EditText etBcc;
private CheckBox cbDeliveryReceipt; private CheckBox cbDeliveryReceipt;
private CheckBox cbReadReceipt; private CheckBox cbReadReceipt;
private Spinner spSent;
private Button btnSave; private Button btnSave;
private ContentLoadingProgressBar pbSave; private ContentLoadingProgressBar pbSave;
@ -123,7 +122,6 @@ public class FragmentIdentity extends FragmentBase {
private long id = -1; private long id = -1;
private int color = Color.TRANSPARENT; private int color = Color.TRANSPARENT;
private ArrayAdapter<EntityFolder> adapter;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@ -175,7 +173,6 @@ public class FragmentIdentity extends FragmentBase {
etBcc = view.findViewById(R.id.etBcc); etBcc = view.findViewById(R.id.etBcc);
cbDeliveryReceipt = view.findViewById(R.id.cbDeliveryReceipt); cbDeliveryReceipt = view.findViewById(R.id.cbDeliveryReceipt);
cbReadReceipt = view.findViewById(R.id.cbReadReceipt); cbReadReceipt = view.findViewById(R.id.cbReadReceipt);
spSent = view.findViewById(R.id.spSent);
btnSave = view.findViewById(R.id.btnSave); btnSave = view.findViewById(R.id.btnSave);
pbSave = view.findViewById(R.id.pbSave); pbSave = view.findViewById(R.id.pbSave);
@ -233,13 +230,10 @@ public class FragmentIdentity extends FragmentBase {
etUser.setText(account.user); etUser.setText(account.user);
tilPassword.getEditText().setText(account.password); tilPassword.getEditText().setText(account.password);
etRealm.setText(account.realm); etRealm.setText(account.realm);
setFolders(account.id);
} }
@Override @Override
public void onNothingSelected(AdapterView<?> adapterView) { public void onNothingSelected(AdapterView<?> adapterView) {
adapter.clear();
} }
}); });
@ -407,10 +401,6 @@ public class FragmentIdentity extends FragmentBase {
} }
}); });
adapter = new ArrayAdapter<>(getContext(), R.layout.spinner_item1, android.R.id.text1, new ArrayList<EntityFolder>());
adapter.setDropDownViewResource(R.layout.spinner_item1_dropdown);
spSent.setAdapter(adapter);
// Initialize // Initialize
Helper.setViewsEnabled(view, false); Helper.setViewsEnabled(view, false);
btnAutoConfig.setEnabled(false); btnAutoConfig.setEnabled(false);
@ -502,7 +492,6 @@ public class FragmentIdentity extends FragmentBase {
args.putString("signature", Html.toHtml(etSignature.getText())); args.putString("signature", Html.toHtml(etSignature.getText()));
args.putBoolean("synchronize", cbSynchronize.isChecked()); args.putBoolean("synchronize", cbSynchronize.isChecked());
args.putBoolean("primary", cbPrimary.isChecked()); args.putBoolean("primary", cbPrimary.isChecked());
args.putSerializable("sent", (EntityFolder) spSent.getSelectedItem());
new SimpleTask<Void>() { new SimpleTask<Void>() {
@Override @Override
@ -546,7 +535,6 @@ public class FragmentIdentity extends FragmentBase {
String bcc = args.getString("bcc"); String bcc = args.getString("bcc");
boolean delivery_receipt = args.getBoolean("delivery_receipt"); boolean delivery_receipt = args.getBoolean("delivery_receipt");
boolean read_receipt = args.getBoolean("read_receipt"); boolean read_receipt = args.getBoolean("read_receipt");
EntityFolder sent = (EntityFolder) args.getSerializable("sent");
if (TextUtils.isEmpty(name)) if (TextUtils.isEmpty(name))
throw new IllegalArgumentException(context.getString(R.string.title_no_name)); throw new IllegalArgumentException(context.getString(R.string.title_no_name));
@ -646,7 +634,7 @@ public class FragmentIdentity extends FragmentBase {
identity.delivery_receipt = delivery_receipt; identity.delivery_receipt = delivery_receipt;
identity.read_receipt = read_receipt; identity.read_receipt = read_receipt;
identity.store_sent = false; identity.store_sent = false;
identity.sent_folder = (sent == null ? null : sent.id); identity.sent_folder = null;
identity.error = null; identity.error = null;
if (identity.primary) if (identity.primary)
@ -838,7 +826,6 @@ public class FragmentIdentity extends FragmentBase {
// OAuth token could be updated // OAuth token could be updated
if (pos > 0 && accounts.get(pos).auth_type != Helper.AUTH_TYPE_PASSWORD) if (pos > 0 && accounts.get(pos).auth_type != Helper.AUTH_TYPE_PASSWORD)
tilPassword.getEditText().setText(accounts.get(pos).password); tilPassword.getEditText().setText(accounts.get(pos).password);
setFolders(account.id);
break; break;
} }
} }
@ -941,64 +928,6 @@ public class FragmentIdentity extends FragmentBase {
vwColor.setBackground(border); vwColor.setBackground(border);
} }
private void setFolders(long account) {
Bundle args = new Bundle();
args.putLong("account", account);
args.putLong("identity", id);
new SimpleTask<IdentityFolders>() {
@Override
protected IdentityFolders onExecute(Context context, Bundle args) {
long aid = args.getLong("account");
long iid = args.getLong("identity");
DB db = DB.getInstance(context);
IdentityFolders result = new IdentityFolders();
result.identity = db.identity().getIdentity(iid);
result.folders = db.folder().getFolders(aid);
if (result.folders != null) {
for (EntityFolder folder : result.folders)
folder.display = folder.getDisplayName(context);
EntityFolder.sort(context, result.folders);
}
return result;
}
@Override
protected void onExecuted(Bundle args, IdentityFolders result) {
EntityFolder none = new EntityFolder();
none.name = "-";
result.folders.add(0, none);
adapter.clear();
adapter.addAll(result.folders);
if (result.identity != null)
for (int pos = 0; pos < result.folders.size(); pos++) {
EntityFolder folder = result.folders.get(pos);
if (result.identity.store_sent) {
if (EntityFolder.SENT.equals(folder.type)) {
spSent.setSelection(pos);
break;
}
} else if (result.identity.sent_folder != null) {
if (result.identity.sent_folder.equals(folder.id)) {
spSent.setSelection(pos);
break;
}
}
}
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex);
}
}.execute(this, args, "identity:folders:get");
}
class IdentityFolders { class IdentityFolders {
EntityIdentity identity; EntityIdentity identity;
List<EntityFolder> folders; List<EntityFolder> folders;

@ -1790,51 +1790,62 @@ public class ServiceSynchronize extends LifecycleService {
db.identity().setIdentityState(ident.id, "connected"); db.identity().setIdentityState(ident.id, "connected");
// Send message // Send message
Address[] to = imessage.getAllRecipients(); Long sid = null;
itransport.sendMessage(imessage, to);
EntityLog.log(this, "Sent via " + ident.host + "/" + ident.user +
" to " + TextUtils.join(", ", to));
db.identity().setIdentityError(ident.id, null);
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancel("send", message.identity.intValue());
// Append replied/forwarded text
if (message.replying != null || message.forwarding != null) {
String html = message.read(this);
html += HtmlHelper.getQuote(this,
message.replying == null ? message.forwarding : message.replying, false);
message.write(this, html);
}
try { try {
db.beginTransaction(); // Append replied/forwarded text
String body = message.read(this);
// Message could be moved if (message.replying != null || message.forwarding != null)
message = db.message().getMessage(message.id); body += HtmlHelper.getQuote(this,
message.replying == null ? message.forwarding : message.replying, false);
EntityFolder sent = db.folder().getFolderByType(ident.account, EntityFolder.SENT);
if (sent != null) {
long id = message.id;
long folder = message.folder;
message.id = null;
message.folder = sent.id;
message.seen = true;
message.ui_seen = true;
message.ui_hide = true;
message.ui_browsed = true; // prevent deleting on sync
message.error = null;
message.id = db.message().insertMessage(message);
message.write(this, body);
sid = message.id;
message.id = id;
message.folder = folder;
message.seen = false;
message.ui_seen = false;
message.ui_browsed = false;
message.ui_hide = false;
}
// Mark message as sent Address[] to = imessage.getAllRecipients();
// - will be moved to sent folder by synchronize message later itransport.sendMessage(imessage, to);
message.sent = imessage.getSentDate().getTime(); EntityLog.log(this, "Sent via " + ident.host + "/" + ident.user +
message.seen = true; " to " + TextUtils.join(", ", to));
message.ui_seen = true;
message.error = null;
db.message().updateMessage(message);
if (ident.store_sent || ident.sent_folder != null) { try {
EntityFolder sent; db.beginTransaction();
if (ident.store_sent)
sent = db.folder().getFolderByType(ident.account, EntityFolder.SENT); if (sid == null) {
else db.message().setMessageSent(message.id, imessage.getSentDate().getTime());
sent = db.folder().getFolder(ident.sent_folder); db.message().setMessageSeen(message.id, true);
if (sent != null) { db.message().setMessageUiSeen(message.id, true);
message.folder = sent.id; db.message().setMessageError(message.id, null);
message.uid = null; message.write(this, body);
db.message().updateMessage(message); } else {
Log.i("Appending sent msgid=" + message.msgid); db.message().setMessageSent(sid, imessage.getSentDate().getTime());
EntityOperation.queue(this, db, message, EntityOperation.ADD); // Could already exist db.message().setMessageUiHide(sid, false);
db.message().deleteMessage(message.id);
//EntityOperation.queue(this, db, message, EntityOperation.ADD);
} }
db.setTransactionSuccessful();
} finally {
db.endTransaction();
} }
if (message.replying != null) { if (message.replying != null) {
@ -1842,9 +1853,14 @@ public class ServiceSynchronize extends LifecycleService {
EntityOperation.queue(this, db, replying, EntityOperation.ANSWERED, true); EntityOperation.queue(this, db, replying, EntityOperation.ANSWERED, true);
} }
db.setTransactionSuccessful(); db.identity().setIdentityError(ident.id, null);
} finally {
db.endTransaction(); NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancel("send", message.identity.intValue());
} catch (Throwable ex) {
if (sid != null)
db.message().deleteMessage(sid);
throw ex;
} }
} catch (MessagingException ex) { } catch (MessagingException ex) {
if (ex instanceof SendFailedException) { if (ex instanceof SendFailedException) {

@ -484,34 +484,6 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbReadReceipt" /> app:layout_constraintTop_toBottomOf="@id/cbReadReceipt" />
<TextView
android:id="@+id/tvSent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_store_copy"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvReceipt" />
<Spinner
android:id="@+id/spSent"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSent" />
<TextView
android:id="@+id/tvSentHint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/title_identity_sent_hint"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="italic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/spSent" />
<Button <Button
android:id="@+id/btnSave" android:id="@+id/btnSave"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -519,7 +491,7 @@
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:text="@string/title_save" android:text="@string/title_save"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSentHint" /> app:layout_constraintTop_toBottomOf="@id/tvReceipt" />
<eu.faircode.email.ContentLoadingProgressBar <eu.faircode.email.ContentLoadingProgressBar
android:id="@+id/pbSave" android:id="@+id/pbSave"

@ -194,7 +194,6 @@
<string name="title_authorize">Select account</string> <string name="title_authorize">Select account</string>
<string name="title_authorizing">Authorizing account &#8230;</string> <string name="title_authorizing">Authorizing account &#8230;</string>
<string name="title_setup_advanced">Advanced</string> <string name="title_setup_advanced">Advanced</string>
<string name="title_store_copy">Store a copy of sent messages in:</string>
<string name="title_synchronize_account">Synchronize (receive messages)</string> <string name="title_synchronize_account">Synchronize (receive messages)</string>
<string name="title_synchronize_identity">Synchronize (send messages)</string> <string name="title_synchronize_identity">Synchronize (send messages)</string>
<string name="title_primary_account">Primary (default account)</string> <string name="title_primary_account">Primary (default account)</string>
@ -214,7 +213,6 @@
<string name="title_account_delete">Delete this account permanently?</string> <string name="title_account_delete">Delete this account permanently?</string>
<string name="title_identity_delete">Delete this identity permanently?</string> <string name="title_identity_delete">Delete this identity permanently?</string>
<string name="title_pop">POP is not supported</string> <string name="title_pop">POP is not supported</string>
<string name="title_identity_sent_hint">Sent messages will automatically be stored in the sent folder already in most cases</string>
<string name="title_edit_html">Edit as HTML</string> <string name="title_edit_html">Edit as HTML</string>
<string name="title_unseen_count" translatable="false">%1$s (%2$d)</string> <string name="title_unseen_count" translatable="false">%1$s (%2$d)</string>

Loading…
Cancel
Save